I am using the python 3.8 client example on my Modbus application, but I get an error like this:
self._sock = context.wrap_socket(self._sock, server_hostname=self._host)
File "/usr/lib/python3.8/ssl.py", line 500, in wrap_socket
return self.sslsocket_class._create(
File "/usr/lib/python3.8/ssl.py", line 1040, in _create
self.do_handshake()
File "/usr/lib/python3.8/ssl.py", line 1309, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: EE certificate key too weak (_ssl.c:1131)
I added the connection codes:
def _do_open(self):
"""Connect to the Modbus slave"""
if self._sock:
self._sock.close()
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_timeout(self.get_timeout())
self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
call_hooks("modbus_tcp.TcpMaster.before_connect", (self, ))
context = SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# context.options |= ssl.OP_NO_SSLv3
context.options |= ssl.OP_NO_TLSv1
# context.options |= ssl.OP_NO_TLSv1_1
context.load_verify_locations('cert.pem')
context.check_hostname = False
# context.verify_mode = ssl.CERT_NONE
# with create_connection((self._host, self._port)) as self._sock:
self._sock.connect((self._host, self._port))
# time.sleep(4)
# print("db:1")
self._sock = context.wrap_socket(self._sock, server_hostname=self._host)
# # print("db:2")
# call_hooks("modbus_tcp.TcpMaster.after_connect", (self, ))
If I added context.verify_mode = ssl.CERT_NONE line for the workaround, it works succefuly but it is not correct way. How Can I solve the problem ?
This is Certificate and Key in Server; (Example key and cert which I found on the github)
const char *privkey = "-----BEGIN PRIVATE KEY-----\n"\
"MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAhD0FKNdH91c8Vis0\n"\
"T7Pli3Grb+BM5xA1V/iNTGer5WSwJlAab6lJ6NNh7R15AXOO7XODOs58ikmEqgWi\n"\
"wacQfwIDAQABAkAG4KeSirPO/OYB80hKtugC2xwX+vn08IZdt2sd5Kxvhzvmp9eM\n"\
"F4QhlQLHOMrk5LkM7FF0G3FgZHlOAZAVbQTtAiEA6SOLWEpnCCEkkCLMmZTcwzV0\n"\
"cX9c7ngnOF/xwIn8IT0CIQCRNJVZ3YcJoXFuOCdUid8qOqdatCDkV8TQNxXxPVSc\n"\
"awIgR1fIMXl7NAKoZK8xeyIRuG7oNj8qWhNMtTSvDyNqk2UCIGgVWi0ldwN3Pviz\n"\
"tbWKcnYxvv5sedtT8pcRtV/MB5drAiBZSqkW9Ha37EObdrctWBvBvHtUp8k9XOy6\n"\
"1X0wxUy5BQ==\n"\
"-----END PRIVATE KEY-----\n";
const char *cert = "-----BEGIN CERTIFICATE-----\n"\
"MIIB2jCCAYSgAwIBAgIIU3U2E0/GMUowDQYJKoZIhvcNAQELBQAwGjEYMBYGA1UE\n"\
"AwwPU3RyYWlnaHQgUm9vdENBMB4XDTIwMTExNTAwMDAwMFoXDTQwMTExNTAwMDAw\n"\
"MFowGjEYMBYGA1UEAwwPU3RyYWlnaHQgU2VydmVyMFwwDQYJKoZIhvcNAQEBBQAD\n"\
"SwAwSAJBAIQ9BSjXR/dXPFYrNE+z5Ytxq2/gTOcQNVf4jUxnq+VksCZQGm+pSejT\n"\
"Ye0deQFzju1zgzrOfIpJhKoFosGnEH8CAwEAAaOBrTCBqjBJBgNVHSMEQjBAgBSD\n"\
"hOKzs+3Mo56OeliOMM0gQZgafKEepBwwGjEYMBYGA1UEAwwPU3RyYWlnaHQgUm9v\n"\
"dENBgghnEtSASbZ0HDAdBgNVHQ4EFgQUGroKNtRTXQ7nxeYSQlZq35oVQDQwDAYD\n"\
"VR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATAbBgNVHREEFDASggZzZXJ2\n"\
"ZXKCCHN0cmFpZ2h0MA0GCSqGSIb3DQEBCwUAA0EAO02jJwxokR4CeA8DDJqp/9Qk\n"\
"0dim//+cjVTjxqIgUS5ykNW2CAIRuP5rVyzNv6U02F0q92Vs/754/ep+TyT70w==\n"\
"-----END CERTIFICATE-----\n";
The output from openssl x509 -text -in cert.pem on your certificate shows:
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (512 bit)
Modulus:
00:84:3d:05:28:d7:47:f7:57:3c:56:2b:34:4f:b3:
512 bit RSA is terrible weak since years. That's what the program is complaining about. You need to create the certificate with a stronger key, like at least 2048 bit RSA.
Most of the answer I've seen did not work for me or was give an unacceptable solution.
The FUTURE policy, it will cause issues. Even if you do the keys at 3072, your fix one item but many other components are failing as well.
e.g.: Git, yum, curl , php ldap...
You don't need to go back to DEFAULT, it's so furstrating when the answer is to go to the weaker and easy way setting, kinda defeat the purpose of securing, this may not be the strongest setting, but still doesn't use the weak crypt while still allowing for lower keys at 2048. prevent error like "too weak".
If 2048 is to low your you. then this is not your answer and you will have to deal with all the sub components. but if you just want to pass the CIS 2 compliance scan. then this does pass for me and this solution also work with the other compenents.
Try:
Step 1: cd /usr/share/crypto-policies/policies
Step 2: sed 's/= 3072/= 2048/g' /usr/share/crypto- policies/policies/FUTURE.pol > FUTURE2048.pol
Step 3: chmod 644 FUTURE2048.pol
Step 4: update-crypto-policies --set FUTURE2048
Step 5: reboot.
This give you all the setting from FUTURE to eliminate weak crypto but still allow for 2048 keys.
Related
I followed this url to create a X509 certificate. And the code is:
from OpenSSL import crypto, SSL
from socket import gethostname
from pprint import pprint
from time import gmtime, mktime
CERT_FILE = "selfsigned.crt"
KEY_FILE = "private.key"
def create_self_signed_cert():
# create a key pair
k = crypto.PKey()
k.generate_key(crypto.TYPE_<wbr>RSA, 1024)
# create a self-signed cert
cert = crypto.X509()
cert.get_subject().C = "UK"
cert.get_subject().ST = "London"
cert.get_subject().L = "London"
cert.get_subject().O = "Dummy Company Ltd"
cert.get_subject().OU = "Dummy Company Ltd"
cert.get_subject().CN = gethostname()
cert.set_serial_number(1000)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(10*<wbr>365*24*60*60)
cert.set_issuer(cert.get_<wbr>subject())
cert.set_pubkey(k)
cert.sign(k, 'sha1')
open(CERT_FILE, "wt").write(
crypto.dump_certificate(<wbr>crypto.FILETYPE_PEM, cert))
open(KEY_FILE, "wt").write(
crypto.dump_privatekey(crypto.<wbr>FILETYPE_PEM, k))
create_self_signed_cert()
But there is something wrong with the code when I run it. Could someone tell me what the meaning of <wbr>? There is a SyntaxError in cert.gmtime_adj_notAfter(10*<wbr>365*24*60*60). Thx.
A version which works with python3
from OpenSSL import crypto, SSL
def cert_gen(
emailAddress="emailAddress",
commonName="commonName",
countryName="NT",
localityName="localityName",
stateOrProvinceName="stateOrProvinceName",
organizationName="organizationName",
organizationUnitName="organizationUnitName",
serialNumber=0,
validityStartInSeconds=0,
validityEndInSeconds=10*365*24*60*60,
KEY_FILE = "private.key",
CERT_FILE="selfsigned.crt"):
#can look at generated file using openssl:
#openssl x509 -inform pem -in selfsigned.crt -noout -text
# create a key pair
k = crypto.PKey()
k.generate_key(crypto.TYPE_RSA, 4096)
# create a self-signed cert
cert = crypto.X509()
cert.get_subject().C = countryName
cert.get_subject().ST = stateOrProvinceName
cert.get_subject().L = localityName
cert.get_subject().O = organizationName
cert.get_subject().OU = organizationUnitName
cert.get_subject().CN = commonName
cert.get_subject().emailAddress = emailAddress
cert.set_serial_number(serialNumber)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(validityEndInSeconds)
cert.set_issuer(cert.get_subject())
cert.set_pubkey(k)
cert.sign(k, 'sha512')
with open(CERT_FILE, "wt") as f:
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8"))
with open(KEY_FILE, "wt") as f:
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8"))
cert_gen()
Just remove <wbr>. So stupid I am.
This is a really useful question; as the referenced link is now dead; and this is one of the first results for searching for "python create ssl certificate".
I would add to it though, that "open(xxx, "wt").write()" is asking for problems later. By not explicitly closing the file, you may find that the garbage collector hasn't run when you try to actually use the file - resulting in a failure.
it's better to use:
with open(xxx, "w") as f:
f.write()
which will ensure that the file is closed when you're done.
With this command it is possible to generate an RSA public-private key pair:
ssh-keygen -f key
Now I would like to load these keys in Python using module cryptography. Example:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
with open("key.pub", "rb") as f:
datapub = f.read()
public_key = serialization.load_ssh_public_key(datapub, backend=default_backend())
But now: How do you generate a fingerprint from this public key? With OpenSSH this can be done using ssh-keygen -lf key.pub. But how do you the same in Python?
First of all: Thank you very much Topaco, you provided the essential hint to me how to generate such a fingerprint. I crosschecked this with other sources on the WWW and can no provide code for anybody to use.
Let's assume we've loaded the key and stored it in public_key. Then a fingerprint can be generated as follows:
rawKeyData = public_key.public_bytes(
encoding=serialization.Encoding.OpenSSH,
format=serialization.PublicFormat.OpenSSH,
)
# prepare for hashing
m = re.match("ssh-rsa ([A-Za-z0-9+/=]+)", rawKeyData.decode("utf-8"))
assert m is not None
base64BinaryData = m.group(1).encode("utf-8")
rawBinaryData = base64.b64decode(base64BinaryData)
# now create the hash
hexDigest = hashlib.md5(rawBinaryData).hexdigest()
# formatting for output similar to "ssh-keygen -l -E md5 -f <pubkeyfile>"
chunks = [ hexDigest[i:i+2] for i in range(0, len(hexDigest), 2) ]
fingerprint = str(self.__public_key.key_size) + "MD5:" + ":".join(chunks) + " (RSA)"
This provides output like this:
2048 MD5:bd:5a:67:a3:4c:46:9d:2c:63:78:7e:68:bc:82:eb:23 (RSA)
The only difference to OpenSSH fingerprints: Here no email address is included in the output.
Some remarks:
regex
I use a regular expression here to parse the output. This is done for safety as this way I ensure that the output matches the expectations of data processing here.
base64
base64 might add padding to the data.
base64 is safe to use as padding is deterministic.
md5
Here the MD5 output is used.
You can safely replace MD5 by any other hash algorithm if you want - e.g. SHA256.
I would like to do some SSL certificate conversions using python, specifically between:
PEM <--> PFX
PEM <--> P7B
I already have a solution for PEM <--> DER.
Namely:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.x509 import (
load_der_x509_certificate,
load_pem_x509_certificate,
)
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
cert = form.cleaned_data.get('file')
der_file = pem_to_der(cert)
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
cert = form.cleaned_data.get('file')
pem_file = der_to_pem(cert)
def pem_to_der(cert):
try:
cert_to_der = load_pem_x509_certificate(cert.read(),
default_backend())
except ValueError:
return False
return cert_to_der.public_bytes(serialization.Encoding.DER)
def der_to_pem(cert):
try:
cert_to_der = load_der_x509_certificate(cert.read(),
default_backend())
except ValueError:
return False
return cert_to_der.public_bytes(serialization.Encoding.PEM)
I do have a solution using subprocess.call, as in:
def pem_to_pfx(private_key_path, cert_path, name, passwd):
return subprocess.call("openssl pkcs12 -export -out " + "tmp/"
+ name + ".pfx" + " -password pass:" + passwd + " -inkey "
+ private_key_path + " -in " + cert_path, shell=True)
but I would prefer to avoid this.
Anybody know of a way to do these conversions using the python module cryptography?
cryptography does not currently support serialization to PKCS12/PFX or PKCS7 (although it can parse PKCS12). The project determines development priorities via user reports with concrete use cases so please file an issue!
As a stopgap you can produce PKCS12 using pyOpenSSL (which uses cryptography's bindings), but we'd prefer to build a good API that you can directly use without an additional dependency.
I used following command to get cert & key from a pks file.
openssl pkcs12 -in ../my.pfx -nocerts -out my.key
openssl pkcs12 -in ~/my.pfx -clcerts -nokeys -out cert.pem
However I keep getting error. I suspect my.key is not correct. How to generate the correct key and cert to feed signxml? I use python3.5 on Ubuntu 16.04. Thank you in advance!
File "/home/ubuntu/.local/lib/python3.5/site-packages/signxml/__init__.py", line 362, in sign
key = load_pem_private_key(key, password=passphrase, backend=default_backend())
File "/home/ubuntu/.local/lib/python3.5/site-packages/cryptography/hazmat/primitives/serialization/base.py", line 16, in load_pem_private_key
return backend.load_pem_private_key(data, password)
File "/home/ubuntu/.local/lib/python3.5/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1025, in load_pem_private_key
password,
File "/home/ubuntu/.local/lib/python3.5/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1218, in _load_key
mem_bio = self._bytes_to_bio(data)
File "/home/ubuntu/.local/lib/python3.5/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 454, in _bytes_to_bio
data_ptr = self._ffi.from_buffer(data)
TypeError: from_buffer() cannot return the address of a unicode object
The sample code from xml page:
cert = open("example.pem").read()
key = open("example.key").read()
root = ElementTree.fromstring(data_to_sign)
signed_root = XMLSigner().sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
I guess it is Python2 vs Python3 thing. All I needed is
key = open("example.key").read().encode('ascii')
I have a hex encoded string which I need to decrypt using RSA_OAEP algorithm.Below is my code snippet:
final_token = decoded_req['token']
print(final_token)
print("Converting actual token into bytes")
## Hex encoded string to bytes
token_to_bytes = bytes.fromhex(final_token)
print(token_to_bytes)
## Read the private key
with open('private.rsa', 'r') as pvt_key:
miPvt = pvt_key.read()
## Decrypt the token using RSA_OAEP
print("Decrypting the token")
rsakey_obj = RSA.importKey(miPvt)
cipher = PKCS1_OAEP.new(rsakey_obj)
dec_token = cipher.decrypt(token_to_bytes)
print(dec_token)
Below is the command line output:
6c79855ca15a3ac0308d17db97a1c576b6f35e4bb630da22867d0d081d55f05e1b1c640d7e7bd8c8de06b6a03e2ef7449e31fa9c0f0c675ebbf838bb880a4c6e309391441e1c41a0c42fbe11eaf6306bb39e7bbbffbe2dbced8c9bb07679ff18cef348b2b7ce08aa05028fda818ac4ce08ad84246c94afbcac405db5258c5333f66148007be8fa5384fa78a0d54ccf26028571180723b2a61fe18ebd0124f7e008902e79b48a53d29953ffde949878b4eb99d376ccf68341b0ec2ceb03b050e7c260f8905dccddb5e50cb331a3bb6bc034fc06dfaf722fd8fad8cb7a311b020be8b1a9115279173b18f46ccc0e28c71f0a6f67e8362a103fa4729057d8924ef0a6fb5a33eeb5b42cdc764fde53b9d6338472fc73e80cf785eb54ffb4ac15a6bf63db19baca586508b8160bf73dbad322221ddb632f5ae8040ef86805a408fc7df6f4a8ee5c7a444a5a13dbdcb8b958c52a8bdc4394e5deaabce203a3ff8675079e6618ac3558cdaf5ce6da77ca667bd5349ba82cc1ad3f71a662a2b7c8b47cc548209264a45a65b3f6f25fedcad8449699a19e2910d24c13b44e3e9445a62f88213346e00048480218996ade7e01151b7e038fbc8a5ff03bfa511126763d4571dec6ce0f5183302a99eee62facabe09211f3a61b8d154a38f0ee9a2647998e2ec1b8ee96b52c443f408cec24140838616c79d82cba4b77171b621f261539e239
Converting actual token into bytes
b'ly\x85\\\xa1Z:\xc00\x8d\x17\xdb\x97\xa1\xc5v\xb6\xf3^K\xb60\xda"\x86}\r\x08\x1dU\xf0^\x1b\x1cd\r~{\xd8\xc8\xde\x06\xb6\xa0>.\xf7D\x9e1\xfa\x9c\x0f\x0cg^\xbb\xf88\xbb\x88\nLn0\x93\x91D\x1e\x1cA\xa0\xc4/\xbe\x11\xea\xf60k\xb3\x9e{\xbb\xff\xbe-\xbc\xed\x8c\x9b\xb0vy\xff\x18\xce\xf3H\xb2\xb7\xce\x08\xaa\x05\x02\x8f\xda\x81\x8a\xc4\xce\x08\xad\x84$l\x94\xaf\xbc\xac#]\xb5%\x8cS3\xf6aH\x00{\xe8\xfaS\x84\xfax\xa0\xd5L\xcf&\x02\x85q\x18\x07#\xb2\xa6\x1f\xe1\x8e\xbd\x01$\xf7\xe0\x08\x90.y\xb4\x8aS\xd2\x99S\xff\xde\x94\x98x\xb4\xeb\x99\xd3v\xcc\xf6\x83A\xb0\xec,\xeb\x03\xb0P\xe7\xc2`\xf8\x90]\xcc\xdd\xb5\xe5\x0c\xb31\xa3\xbbk\xc04\xfc\x06\xdf\xafr/\xd8\xfa\xd8\xcbz1\x1b\x02\x0b\xe8\xb1\xa9\x11Ry\x17;\x18\xf4l\xcc\x0e(\xc7\x1f\nog\xe86*\x10?\xa4r\x90W\xd8\x92N\xf0\xa6\xfbZ3\xee\xb5\xb4,\xdcvO\xdeS\xb9\xd63\x84r\xfcs\xe8\x0c\xf7\x85\xebT\xff\xb4\xac\x15\xa6\xbfc\xdb\x19\xba\xcaXe\x08\xb8\x16\x0b\xf7=\xba\xd3""\x1d\xdbc/Z\xe8\x04\x0e\xf8h\x05\xa4\x08\xfc}\xf6\xf4\xa8\xee\\zDJZ\x13\xdb\xdc\xb8\xb9X\xc5*\x8b\xdcC\x94\xe5\xde\xaa\xbc\xe2\x03\xa3\xff\x86u\x07\x9ef\x18\xac5X\xcd\xaf\\\xe6\xdaw\xcaf{\xd54\x9b\xa8,\xc1\xad?q\xa6b\xa2\xb7\xc8\xb4|\xc5H \x92d\xa4Ze\xb3\xf6\xf2_\xed\xca\xd8D\x96\x99\xa1\x9e)\x10\xd2L\x13\xb4N>\x94E\xa6/\x88!3F\xe0\x00HH\x02\x18\x99j\xde~\x01\x15\x1b~\x03\x8f\xbc\x8a_\xf0;\xfaQ\x11&v=Eq\xde\xc6\xce\x0fQ\x830*\x99\xee\xe6/\xac\xab\xe0\x92\x11\xf3\xa6\x1b\x8d\x15J8\xf0\xee\x9a&G\x99\x8e.\xc1\xb8\xee\x96\xb5,D?#\x8c\xec$\x14\x088aly\xd8,\xbaKw\x17\x1bb\x1f&\x159\xe29'
Decrypting the token
Traceback (most recent call last):
File "script.py", line 80, in <module>
dec_token = cipher.decrypt(token_to_bytes)
File "/home/venv/lib/python3.6/site-packages/Crypto/Cipher/PKCS1_OAEP.py", line 201, in decrypt
raise ValueError("Incorrect decryption.")
ValueError: Incorrect decryption.
Can someone help me in resolving this issue?
I suspect you have not correctly transferred your encrypted token. But there isn't a lot to go on.
I've used you example code though to help me write the below which does seem to work, (thank you for that) or at least it decrypted a value from another implementation.
In my case it was a node JS implementation
var nodeRsa = require("node-rsa");
const key = new nodeRsa( "-----BEGIN PUBLIC KEY-----\n\
.
.
.
-----END PUBLIC KEY-----");
key.encrypt("passwd","base64");
If I took the output of the above and put in a file called 'ciphertext', this following python decrypts the message correctly.
import Crypto.Cipher.PKCS1_OAEP as rsaenc
import Crypto.PublicKey.RSA as RSA
import codecs
## Load the private key and the base 64 ciphertext.
with open("key.pem") as f:
keystring = f.read()
with open("ciphertext","rb") as f:
base64msg = f.read()
# Create the binary ciphertext
binmsg=codecs.decode(base64msg,'base64')
# Setup the RSA objetcs
k = RSA.importKey(keystring)
cipher = rsaenc.new(k)
plaintext = cipher.decrypt(binmsg)
print (plaintext)