Hi all, I'm dealing with a C++ client & server pair that uses ECDSA to verify the server's identity. I'm trying to write a new Python client that will exchange with the server without making any changes to the server. I've gotten quite a bit of this in place with cryptography (the Python package :-), but I'm incapable of getting the Python client to verify the signature sent by the server and I'd like to see if you can help me out.
One of the problems here is that the serialization formats seem to be internal to Microsoft's CNG API. For example, the public key is the raw output of BCryptExportKey() and the signature is the raw output of BCryptSignHash(). These are Microsoft APIs, so... needless to say cryptography doesn't "just work" with these formats. I'm pretty sure I managed to nail the key format conversion as Microsoft makes an obscure reference to the format[1], but I'm still having trouble with signatures. The blob I get as output from BCryptSignHash() has 64 bytes, but signatures for the same algorithm using cryptography are usually 70-72 bytes, so I'm confused. Cryptography's ECC signature computation clearly documents the format: "The signature is formatted as DER-encoded bytes, as specified in RFC 3279." However, Microsoft doesn't seem to output record an equivalent anywhere. They're usually pretty consistent with their APIs and storage formats, so I assume some sort of storage similar to the keys where we have two 32-byte octet streams in big endian format containing the values for R and S, but I haven't had any luck with this. I also know that the DER encoding for two integer fields will normally add 6 bytes of overhead, which gets us up to 70, but there is still the occasional extra 1 or 2 bytes, so I'm obviously missing something and may not be on the right track. [1] :https://msdn.microsoft.com/library/aa375520.aspx Anyways, I managed to extract the BCrypt* function calls from the server and client into a pair of C++ program the contain only the signing and signature verification code to reproduce the flow. The total is ~30 lines of C++ code on each side, plus ~400 lines wrappers for BCrypt* calls (resource management, error handling and links to CNG API docs). I've also written a small cryptography-based Python program that tries to mimic the C++ client and I cannot get that part to run. If anyone has a few minutes to spare to give my Python code a second pair of eyeballs, I'd really appreciate it. I've saved up all of that on this Gist: https://gist.github.com/AndreLouisCaron/ab5ee411d0722a0981feceddbf5cb3d9 The gist contents are as follows: - genkeys.py: generate a public/private key pair, write to disk in Microsoft's format; - server.cpp: load secret key, compute signature, save payload & signature to disk; - client.cpp: load public key, payload & signature from disk, verify signature; - common.h: stuff shared by client.cpp & server.cpp; - client.py: same as client.cpp, but using cryptography. I also have an alternate C++ client based on OpenSSL which might be a better source of inspiration. I'll see if I can extract pars of that too as a reference since it might be easier to map to cryptography's internals. Thanks in advance, André
_______________________________________________ Cryptography-dev mailing list Cryptography-dev@python.org https://mail.python.org/mailman/listinfo/cryptography-dev