I'm trying to use the OpenSSL built in PHP library to get the content of a p7m signed file
I'm trying to "translate" this using openssl_pkcs7_verify():
openssl smime -verify -in DATA/test.ecs -inform der -binary -out DATA/test.enc.txt -CAfile CA.pem
The OpenSSL library needs S / MIME and not DER, so I use this function to get the file as S / MIME:
function der2pem($der_data) {
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "MIME-Version: 1.0\nContent-Disposition: attachment; filename=\"smime.p7m\"\nContent-Type: application/x-pkcs7-mime; smime-type=signed-data; name=\"smime.p7m\"\nContent-Transfer-Encoding: base64\n\n".$pem;
return $pem;
}
PHP Code:
$decrypt_file_name = 'DATA/test.ecs';
$data = der2pem(file_get_contents($decrypt_file_name));
$out = fopen($decrypt_file_name, "w");
fwrite($out,$data);
fclose($out);
openssl_pkcs7_verify(
realpath($decrypt_file_name),
0,
'CA.pem',
[],
'CA.pem',
$output,
'DATA/test.enc.txt'
); // Return error: error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error
How i can traslate the shell command to openssl php library? Thanks in advance!
Related
I created a P8 format Private Key and signed data Using Java and tried to verify it using Public Key in PHP which Failed.
I created p8 file using openssl command
openssl pkcs8 -topk8 -inform PEM -outform DER -in myprivate.in.key -out myprivate.in.key.p8 -nocrypt
and Signed a Json data using
public byte[] sign(String data, String privateKeyFilePath) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException {
byte[] returnVal = null;
Signature signature = Signature.getInstance(RSA_SHA_256);
PrivateKey privateKey = getPrivateKey(privateKeyFilePath);
signature.initSign(privateKey);
signature.update(data.getBytes());
returnVal = signature.sign();
return returnVal;
}
But When I tried to verify it using Public cerificate in PHP using openssl command, it failed
$cert_path = file_get_contents(storage_path('certificates/my_in.cer'));
$pub_key = openssl_get_publickey($cert_path);
$keyData = openssl_pkey_get_details($pub_key);
$pub_key = $keyData['key'];
// $verify = openssl_x509_verify()
$verify = openssl_verify($dataSigned, $signatureDecoded, $pub_key, 'sha256WithRSAEncryption');
What am I doing wrong, Also is there a way I can Sign the data using p8 key in php!
By following this process everything is ok. Maybe it will be useful to you?
Use openssl to generate keys:
# Generate PK
openssl genpkey -algorithm RSA \
-pkeyopt rsa_keygen_bits:2048 \
-pkeyopt rsa_keygen_pubexp:65537 | \
openssl pkcs8 -topk8 -nocrypt -outform der > rsa-2048-private-key.p8
# Convert your PKCS#8 file to a plain private key
openssl pkcs8 -nocrypt -in rsa-2048-private-key.p8 -inform DER -out rsa-2048-private-key.pem
# Generate pub key
openssl rsa -in rsa-2048-private-key.pem -pubout -out rsa-2048-public-key.pem
Test pkey and sign data (index.php):
<?php
$privateKeyFile="file://".__DIR__.DIRECTORY_SEPARATOR."rsa-2048-private-key.pem";
$publicKeyFile="file://".__DIR__.DIRECTORY_SEPARATOR."rsa-2048-public-key.pem";
// Data to sign
$data = 'Hello world!';
// Test on get private key
$pkeyid = openssl_pkey_get_private($privateKeyFile);
if ($pkeyid === false) {
var_dump(openssl_error_string());
}else{
var_dump($pkeyid);
}
// Sign data
openssl_sign($data, $signature, $pkeyid);
// Free memory
openssl_free_key($pkeyid);
// Read pub key
$pubkeyid = openssl_pkey_get_public($publicKeyFile);
// Test if sign is ok
$ok = openssl_verify($data, $signature, $pubkeyid);
if ($ok == 1) {
echo "Sign OK";
} elseif ($ok == 0) {
echo "Sign NOK";
} else {
echo "Sign check error";
}
// Free memory
openssl_free_key($pubkeyid);
php -S localhost:8000, http://localhost:8000, returns:
resource(2) of type (OpenSSL key) Sign OK
I am encrypting a password in PHP, and want to decrypt it on a different box. I am having no luck and I would prefer to be able to decrypt it right from bash and echo it. Below is a snippet of a test in PHP.
$textToEncrypt = "My super secret information.";
$encryptionMethod = "AES-256-CBC";
$secretHash = "Testkey";
//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash);
//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash);
//Result
echo "Encrypted: $encryptedMessage <br>Decrypted: $decryptedMessage";
I have tried numerous methods to decrypt it on Ubuntu, even storing the data to a file and outputting it to a file. Command tried was:
openssl aes-256-cbc -a -d -k Testkey -in foo.txt -out secrets.txt
Where foo.txt is the value returned from the PHP encryption, and secrets.txt is the output. How can I do this?
It bears repeating, as in the comments, that encryption without an IV is dangerous. In fact, the current version of PHP will issue a warning about it. IVs can be randomly generated using the openssl_random_pseudo_bytes() function, and transmitted in the clear along with the encrypted text. They don't have to be secret, the important thing is not to reuse the same key and IV combination, and have a random IV.
So, with that out of the way, if you take a look at the source for the function, it's not passing the password argument as a passphrase, but rather as the key. So for using openssl on the command line, it needs to be in hex and passed to the -K option, not the -k option. But then, you'll get an error back saying "iv undefined" so your PHP needs to be adjusted to include one:
<?php
$textToEncrypt = "My super secret information.\n";
$encryptionMethod = "AES-256-CBC";
$key = "Testkey";
$iv = openssl_random_pseudo_bytes(
openssl_cipher_iv_length($encryptionMethod)
);
$keyHex = bin2hex($key);
$ivHex = bin2hex($iv);
//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $key, 0, $iv);
//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $key, 0, $iv);
//Result
printf(
"Decrypted message: %s\n\nkeyHex=%s\nivHex=%s\nencryptedMessage=%s\n",
$decryptedMessage,
escapeshellarg($keyHex),
escapeshellarg($ivHex),
escapeshellarg($encryptedMessage)
);
Once you have these details, you can decrypt from command line (re-using PHP variable names here):
echo -n "$encryptedMessage" | openssl aes-256-cbc -d -a -A -K "$keyHex" -iv "$ivHex"
The other way around
#!/bin/bash
# create in bash keys
echo "generating private key"
openssl genrsa -out privkey.pem 2048
echo "signing private key"
openssl req -new -key privkey.pem -out certreq.csr -subj "/C=RO/ST=AB L=AB/O=None/OU=Department/CN=someweb.com"
echo "create a sign request"
openssl x509 -req -in certreq.csr -signkey privkey.pem -out newcert.pem
# end-of-bash-script
cp ./privkey.pem /path/to/apache/root/<some>
Encrypt some json file
openssl smime -encrypt -aes256 -in ./json.txt -binary -outform DER -out ./json.xxx newcert.pem
# test decrypt here in bash
# openssl smime -decrypt -in json.xxx -inform DER -inkey privkey.pem -out json.dec
Post it as binary to php
curl --request POST --data-binary #./json.xxx http://localhost/<some/>json.php
Then json.php script # apache root
<?php
$rkey = file_get_contents("/var/www/html/privkey.pem");
$pkey = file_get_contents("/var/www/html/newcert.pem");
$data = file_get_contents("php://input");
$fenc = tempnam("", "enc");
$fdec = tempnam("", "dec");
file_put_contents($fenc,$data);
// openssl_pkcs7_decrypt ($fenc , $fdec , $pkey, $rkey ); unable to coerce parameter 3 to x509 cert
system("openssl smime -decrypt -in ${fenc} -inform DER -inkey privkey.pem -out ${fdec}");
echo file_get_contents($fdec);
?>
I am trying to create the server side connection for apple push notifications.
First, I ask from the user (who probably will be an ios dev) to give the .cer and .p12 files that Apple provides in order to make it a .pem file.
Below is the .pem certificate creation.
$dir = $this->directory.'/certificates';
$password = 'a_user_password';
$certificate = $dir.'/certificate.cer';
$key_password = $dir.'/key.p12';
exec('openssl x509 -inform der -in '.$certificate.' -out '.$dir.'/certificate.pem');
exec('openssl pkcs12 -nocerts -out '.$dir.'/key.pem -in '.$key_password.' -passout pass:'.$password.' -passin pass:'.$password);
$filename = $key_password;
$results = array();
$worked = openssl_pkcs12_read(file_get_contents($filename), $results, $obj->password);
if($worked) {
$current = file_get_contents($dir.'/key.pem');
$current .= $results['pkey'];
file_put_contents($dir.'/key.pem', $current);
} else {
echo openssl_error_string();
}
exec('cat '.$dir.'/certificate.pem '.$dir.'/key.pem > '.$dir.'/apns_certificate.pem');
So far, so good. I have tested that the above generated apns_certificate.pem is successful with apple through command line via:
s_client -connect gateway.sandbox.push.apple.com:2195 -cert certificate.pem -key key.pem
However,
When I try to connect with apns through PHP I cannot. Follows the last php code that I have tried and I have seen that for others has worked:
$this->certificate = ROOT.'/certificates/apns_certificate.pem';
$this->socket = 'ssl://gateway.push.apple.com:2195';
if (!file_exists($this->certificate)) {
$this->error = 'Certificate file not found';
return false;
}
$this->stream_context = stream_context_create();
$this->stream_options = array(
'ssl' => array(
'local_cert' => $this->certificate,
'passphrase' => 'a_user_password', //same with the one used in my previous code
)
);
$success = stream_context_set_option($this->stream_context, $this->stream_options);
if ($success == false) {
$this->error = 'Secure connection failed';
return false;
}
$this->socket_client = stream_socket_client($this->socket, $con_error, $con_error_string, $this->timeout, STREAM_CLIENT_CONNECT, $this->stream_context);
if ($this->socket_client === false) {
$this->error = $con_error_string;
return false;
} else {
return true;
}
The above code returns me an error:
Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:14094416:SSL routines:SSL3_READ_BYTES:sslv3 alert certificate unknown
Warning: stream_socket_client(): unable to connect to ssl://gateway.push.apple.com:2195
Thank you in advance for your help!
The above code is correct. There was an error with the certification .p12 . Also I changed the exec for .p12 convertion file to:
exec('openssl pkcs12 -out '.$dir.'/key.pem -in '.$key_password.' -passout pass:'.$password.' -passin pass:'.$password.' -nodes');
I've been trying to duplicate this command using PHP's built in openssl functions with no luck. I've tried variations of openssl_pkcs7_sign and openssl_pkcs7_encrypt. I believe the issue is that there is no flag to indicate the DER format output.
Here is the openssl command I am trying to replicate:
openssl smime -sign -signer mycert.pem -certfile mybundle.crt -inkey mykey.pem -nodetach -outform der -in file_in -out file_out
openssl_pkcs7_sign indeed signs the data in PEM format but you can just take the base64 chunk of the PEM data and convert it to DER by using base64_decode().
function get_base64($file_name) {
$content = file($file_name, FILE_IGNORE_NEW_LINES);
$base64_data = "";
for ($i=5; $i<sizeof($content); $i++){ // take only the base64 chunk
$base64_data .= $content[$i];
}
return $base64_data;
}
function pem2der($base64_data) {
$der = base64_decode($base64_data);
return $der;
}
if (openssl_pkcs7_sign( // Signs file_in and saves as file_out in PEM format
"file_in", // Input file
"file_out", // Output file (PEM format)
"file://../.pki/company.crt", // Certificate (mycert.pem)
"file://../.pki/company.key", // Private key (mykey.pem)
array(),
PKCS7_NOATTR,
"../.pki/company.cacrt" // Intermediate certificate (mybundle.crt)
)) {
$data = pem2der(get_base64("file_out")); // converts content of file_out to DER format
$out = fopen("file_out", "w") or die("Unable to open file!");
fwrite($out,$data); // output file (DER format)
fclose($out);
echo("File signed successfully!")
}
?>
I have a crypto/php question, I was hoping someone could help me with.
My issue is that I have a signed PKCS7 block that I am trying to verify in PHP.
However, when I run the following PHP command:
openssl_pkcs7_verify($myfile, PKCS7_BINARY | PKCS7_NOVERIFY, $signers_file);
I get the following error:
PKCS7 routines:SMIME_read_PKCS7:no content type
If I do it using ruby like so:
p7container = OpenSSL::PKCS7.new(file_contents);
mystore = OpenSSL::X509::Store.new
p7container.verify(nil, store, nil, OpenSSL::PKCS7::NOVERIFY)
It works.
Also, if I run it through the OpenSSL commandline:
openssl smime -verify -inform der -in my_data_file -noverify
It also works. However, if I run the following:
openssl smime -verify -in my_data_file -noverify
Which is the same command, but without specifying the inform parameter, it fails with the same error message specified before, regarding the "no content type", which makes it seem I need to specify the input file format. Any ideas how I can do that through PHP?
Thanks in advance for your help,
I got around that problem by calling openssl directly from PHP (using the exec function). Be sure to add 2>&1 to the command to redirect stderr to stdout as the message "Verification successful" is sent to stderr.
function verify($signedData, &$data = null) {
#mkdir("tmp");
$random = randomString(32);
$signedFile = "tmp/" . $random . ".pem";
$file = "tmp/" . $random . ".dat";
file_put_contents($signedFile, $signedData);
$output = exec("openssl smime -verify -in $signedFile -inform DER -noverify -out $file 2>&1");
if ($output == "Verification successful") {
$data = file_get_contents($file);
$result = true;
} else {
$result = false;
}
#unlink($signedFile);
#unlink($file);
return $result;
}