OpenSSL and Private Key Compromise

This is a problem I've run into several times in the past, so I wanted to document this a bit. While processing certificate signing requests (CSR's) I've occasionally had external entities send the private key along with the CSR. I guess they assume it's needed for some reason... Needless to say, I ask that they ensure a new private key is generated and send me a new CSR without the private key.

Trust but verify

How do I make sure they used a new private key without seeing the private key? The CSR contains, among the usual metadata that you see in CSR decoders, the public key that will be used. Remember, in asymmetric encryption, anything the public key encrypts, the private key decrypts and vice-versa.

So our process goes like this. Extract the public key from the CSR, encrypt something with the public key, see if the private key decrypts it. Going one step at a time...

Extract the public key from the CSR
openssl req -in someserver.csr -noout -pubkey > someserver_public.crt
Encrypt something with the public key
echo 'This is a test.' | openssl rsautl -encrypt -pubin -inkey someserver_public.crt > message.encrypted
Decrypt that something with the private key
openssl rsautl -decrypt -in message.encrypted -out message.decrypted -inkey someserver_PRIVATE.crt
If, at this point, you get a message "block type is not 02" and/or "padding check failed", then the private key used to generate the CSR is different. This site talks about these errors: http://hustoknow.blogspot.com/2013/01/rsa-block-type-is-not-02-error.html
If, on the other hand, you get no errors and can "cat message.decrypted" and see your original "This is a test." message, then the private key was used to sign that message.

Within the browser, you can also export/save/copy the certificate to a file (Base64 encoded x509 CER). We can then extract the public key from this as well and perform the same operations to ensure they did not use the wrong cert or that a cert has been properly replaced.
openssl x509 -pubkey -noout -in someserver_browsercert.cer > someserver_public_frombrowser.crt
Then test the encryption/decryption process with the private cert.

Lastly, just as a note, OpenSSL has a ton of options, I'm aware that most of these have outfile flags instead of redirecting input, and vice versa with the decrypted messages. Everyone is going to have their own way of doing it, whatever works for you. I just wanted to state that for anyone with no OpenSSL experience. You could also encrypt something with the private key and decrypt it with the public, either one works.