I use the following script to generate a new signed certificate:
<?php
error_reporting(E_ALL);
// Generate a new private (and public) key pair
$privkey = openssl_pkey_new();
// Generate a certificate signing request
$dn = array(
"countryName" => "US",
"stateOrProvinceName" => "Atlantis",
"localityName" => "NeverEverLand",
"organizationName" => "only me",
"organizationalUnitName" => "blah",
"commonName" => "bleh",
"emailAddress" => "test#test.com"
);
$csr = openssl_csr_new($dn, $privkey);
$cacert = file_get_contents('ca.crt');
echo $cacert . "<BR/>";
echo "<BR/>";
$ca_key = file_get_contents('ca.key');
$cakey = array($ca_key, "mysecretpass");
echo $ca_key . "<BR/>";
echo "<BR/>";
$sscert = openssl_csr_sign($csr, $cacert, $cakey, 365);
var_dump($sscert);
echo "<BR/>";
echo "<BR/>";
openssl_pkey_export($privkey, $pkeyout, "mypassword"); var_dump($pkeyout);
echo "<BR/>";
echo "<BR/>";
openssl_csr_export($csr, $csrout); var_dump($csrout);
echo "<BR/>";
echo "<BR/>";
openssl_x509_export($sscert, $certout); var_dump($certout);
echo "<BR/>";
echo "<BR/>";
while (($e = openssl_error_string()) !== false) {
echo $e . "\n";
}
?>
As you can see in the output it can read ca.crt and ca.key. The pass is also correct (changed in above source).
This is the output of the script:
-----BEGIN CERTIFICATE----- MIIFGDCCAwACCQCO584jngEQdjANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV ... XZ8YaIOkiV4pEiR5 -----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,E616BBF003C1FA9D ... VCPNIOlGzmKUvDn0iMKE0KRmN8o3ip8oy4HKPZmuh4h+qznZdNF/pBTurqcNVN/P -----END RSA PRIVATE KEY-----
bool(false)
string(1834) "-----BEGIN ENCRYPTED PRIVATE KEY----- MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIBX0RFXQVx+ICAggA Bfw= -----END ENCRYPTED PRIVATE KEY----- "
string(1045) "-----BEGIN CERTIFICATE REQUEST----- MIICzDCCAbQCAQAwgYYxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhBdGxhbnRpczEW zZL71nx/8MgG8hyg63vRRJewb/cCIt1q9A4SwGB9iDe75CbR3ij3jHMftXUfvYhV -----END CERTIFICATE REQUEST----- "
NULL
so the command
openssl_csr_sign($csr, $cacert, $cakey, 365);
returns FALSE, even if all input parameters are valid.
Using CentOS 6.4 / Apache/2.2.15 (CentOS) / mod_ssl/2.2.15
Related
I am trying to generate a JWT for the DocuSign Embed API and I can't seem to figure out the private/public key part.
When I generate the JWT, the signature part is very short. Pasting it in jwt.io, it turns out both the header and payload are correct, but the signature part is wrong (and way too short when I compare it to what I get when I copy paste my public and rsa private keys.
Here is the relevant code:
$args = [
'envelope_id' => $_GET['envelope_id'],
'ds_return_url' => 'https://www.returnurl.be',
'starting_view' => 'envelope',
'base_path' => 'https://baseurl.be'
];
$args['integration_key'] = 'abc123';
if(isset($_GET['user_id'])) {
$args['user_id'] = $_GET['user_id'];
}
//generate jwt:
$headers = array('alg'=>'RS256','typ'=>'JWT');
$payload = array(
'iss'=>$args['integration_key'],
'sub'=>$args['user_id'],
'aud'=>'account-d.docusign.com', //prod: account.docusign.com
'iat'=>time(),
'exp'=>(time() + 6000),
'scope'=>'signature impersonation'
);
$secret = '-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAj...
-----END RSA PRIVATE KEY-----';
$jwt = generate_jwt($headers, $payload, $secret);
echo $jwt;
function generate_jwt($headers, $payload, $secret = 'secret') {
$headers_encoded = base64url_encode(json_encode($headers));
$payload_encoded = base64url_encode(json_encode($payload));
$signature = hash_hmac('SHA256', "$headers_encoded.$payload_encoded", $secret, true);
$signature_encoded = base64url_encode($signature);
$jwt = "$headers_encoded.$payload_encoded.$signature_encoded";
return $jwt;
}
function base64url_encode($str) {
return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
}
I am generating a RSA signature in PHP By PHPSECLIB library. According to the instructions, the signature digest must be sha256. Should the digest be set when the key is generated?
I generated Pub/Pri key by blow code: (It should be 2048 and .perm)
$new_key_pair = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
openssl_pkey_export($new_key_pair, $private_key_pem);
$details = openssl_pkey_get_details($new_key_pair);
$public_key_pem = $details['key'];
file_put_contents('private.pem', $private_key_pem);
file_put_contents('public.pem', $public_key_pem);
I sign data by blow code:
$file_name = "x.json";
$sign_file = "signed/" . $file_name . ".sign";
$data = file_get_contents('files/' . $file_name);
$privatekey = file_get_contents('private.pem');
$rsa = new Crypt_RSA();
$rsa->loadKey($privatekey);
$rsa->setHash('sha256');
$signature = $rsa->sign($data);
file_put_contents($sign_file, $signature);
exit("signed.");
and verify it by
$file_name = "x.json";
$sign_file = "signed/" . $file_name . ".sign";
$publickey = file_get_contents('public.pem');
$data = file_get_contents('files/' . $file_name);
$signature = file_get_contents($sign_file);
$rsa = new Crypt_RSA();
$rsa->setHash('sha256');
$rsa->loadKey($publickey);
$verify = false;
try {
$verify = $rsa->verify($data, $signature);
} catch (Exception $ex) {
$verify = false;
}
echo "verify: " . (($verify) ? "true" : "false") . "<br>";
exit("finished.");
How to set up a digest? Is the signing process correct?
I can create S/MIME certificate on command line just fine:
openssl genrsa -out some_cert.key 4096
openssl req -new -key some_cert.key -out some_cert.csr
And then sign the certificate by my own authority:
openssl x509 -req -in some_cert.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out some_cert.crt
And subsequently import it to Thunderbird as a 'People's' certificate.
But - on the very same Linux machine (i.e. the same OpenSSL cnf) - I cannot do that in PHP:
$directory = "/tmp";
$path = "/path/to/authority";
$ca = file_get_contents($path . '/ca.crt');
$cakey = array(file_get_contents($path . '/ca.key'), "authorityKeyPass");
$dn = array(
"countryName" => "UK",
"stateOrProvinceName" => "Scotland",
"localityName" => "Aberdeen",
"organizationName" => "Someorg",
"organizationalUnitName" => "Someunit",
"commonName" => foo#domain.org,
"emailAddress" => foo#domain.org
);
$config = array(
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
'x509_extensions' => 'v3_ca',
);
// Generate a new private key
$privkey = openssl_pkey_new($config);
// Generate a certificate signing request
$csr = openssl_csr_new($dn, $privkey);
// Sign certificate
$sscert = openssl_csr_sign($csr, $ca, $cakey, 365);
// Export CRT (public key)
openssl_x509_export($sscert, $certout);
// Save to file
file_put_contents('/tmp/serverCASigned.crt', $certout);
File is correctly saved, but I cannot import it to Thunderbird as a 'People's' certificate: No error message, just the import dialogue is closed and certificate isn't imported.
And the size of command-line generated .crt file is different from size of file generated in php...
It indeed was the signing part.
The best solution for it I have found is to use phpseclib:
// Load the library phpseclib
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
include_once('File/X509.php');
include_once('Crypt/RSA.php');
// CA Private key
$CAPrivKey = new Crypt_RSA();
$CAPrivKey->setPassword("authorityKeyPass");
$CAPrivKey->loadKey(file_get_contents($path . "/ca.key"));
// CA Authority
$issuer = new File_X509();
$issuer->setPrivateKey($CAPrivKey);
$issuer->loadX509(file_get_contents($path . "/ca.crt"));
// Subject - who will be signed by authority
$subject = new File_X509();
$subject->loadCSR($csrout);
// And sign it
$x509 = new File_X509();
$x509->setStartDate('-1 month');
$x509->setEndDate('+5 year');
$x509->setSerialNumber(mt_rand(1, 2147483647) . mt_rand(1, 2147483647));
$result = $x509->sign($issuer, $subject);
// Save to file
file_put_contents('/tmp/serverCASigned.crt', $x509->saveX509($result));
And all runs fine...
I would like to communicate with the Apple Push Notification Service from a PHP script.
But I keep getting following error:
Warning: stream_socket_client(): Unable to set private key file
I have a .pem-file which looks like this:
-----BEGIN CERTIFICATE-----
Encrypted String
-----END CERTIFICATE-----
Bag Attributes
friendlyName: ...
localKeyID: ...
Key Attributes: ...
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: ...
DEK-Info: ...
Encrypted String
-----END RSA PRIVATE KEY-----
I am running the PHP script from sudo. It can find my .pem file, because if I remove it, I get a "handshake failure" error instead.
What could be wrong here?
I recently made a script to send remote pushnotifications.
This is how I did it:
$message = "A cool message!";
$deviceid = "";
$count = 0;
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns-dev.pem');
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
echo 'Failed to connect ' . $err . $errstr;
} else {
$payloads['aps'] = array('alert' => $message, 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payloads);
$msg = chr(0) . pack('n',32) . pack('H*', $deviceid) . pack('n',strlen($payload)) . $payload;
fwrite($fp, $msg);
$count += 1;
fclose($fp);
}
echo 'Sended: ' . $count;
I got it working. It turns out I exported my private key which I generated for the push notifications instead of the corresponding certificate.
How can I use openssl when accessing data using PHP 5.3?
I hope I can get how to use it. Please give me an example as how to access data using OpenSSL.
Do you want to generate a pair of keys with php?
$NEW_KEY = openssl_pkey_new(array(
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
));
openssl_pkey_export_to_file($NEW_KEY, 'private.key');
$NEW_KEY_DETAILS = openssl_pkey_get_details($NEW_KEY);
file_put_contents('public.key', $NEW_KEY_DETAILS['key']);
openssl_free_key($NEW_KEY);
Do you already have the keys ?
$public = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfmlc2EgrdhvakQApmLCDOgP0n
NERInBheMh7J/r5aU8PUAIpGXET/8+kOGI1dSYjoux80AuHvkWp1EeHfMwC/SZ9t
6rF4sYqV5Lj9t32ELbh2VNbE/7QEVZnXRi5GdhozBZtS1gJHM2/Q+iToyh5dfTaA
U8bTnLEPMNC1h3qcUQIDAQAB
-----END PUBLIC KEY-----";
$private = "-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDfmlc2EgrdhvakQApmLCDOgP0nNERInBheMh7J/r5aU8PUAIpG
XET/8+kOGI1dSYjoux80AuHvkWp1EeHfMwC/SZ9t6rF4sYqV5Lj9t32ELbh2VNbE
/7QEVZnXRi5GdhozBZtS1gJHM2/Q+iToyh5dfTaAU8bTnLEPMNC1h3qcUQIDAQAB
AoGAcbh6UFqewgnpGKIlZ89bpAsANVckv1T8I7QT6qGvyBrABut7Z8t3oEE5r1yX
UPGcOtkoRniM1h276ex9VtoGr09sUn7duoLiEsp8aip7p7SB3X6XXWJ9K733co6C
dpXotfO0zMnv8l3O9h4pHrrBkmWDBEKbUeuE9Zz7uy6mFAECQQDygylLjzX+2rvm
FYd5ejSaLEeK17AiuT29LNPRHWLu6a0zl923299FCyHLasFgbeuLRCW0LMCs2SKE
Y+cIWMSRAkEA7AnzWjby8j8efjvUwIWh/L5YJyWlSgYKlR0zdgKxxUy9+i1MGRkn
m81NLYza4JLvb8/qjUtvw92Zcppxb7E7wQJAIuQWC+X12c30nLzaOfMIIGpgfKxd
jhFivZX2f66frkn2fmbKIorCy7c3TIH2gn4uFmJenlaV/ghbe/q3oa7L0QJAFP19
ipRAXpKGX6tqbAR2N0emBzUt0btfzYrfPKtYq7b7XfgRQFogT5aeOmLARCBM8qCG
tzHyKnTWZH6ff9M/AQJBAIToUPachXPhDyOpDBcBliRNsowZcw4Yln8CnLqgS9H5
Ya8iBJilFm2UlcXfpUOk9bhBTbgFp+Bv6BZ2Alag7pY=
-----END RSA PRIVATE KEY-----";
if (!$privateKey = openssl_pkey_get_private($private)) die('Loading Private Key failed');
if (!$publicKey = openssl_pkey_get_public($public)) die('Loading Public Key failed');
$encrypted = '';
$decrypted = '';
$plaintext = 'This is just some text to encrypt';
echo '<p>$plaintext = ' . $plaintext . '<p>';
if (!openssl_public_encrypt($plaintext, $encrypted, $publicKey)) die('Failed to encrypt data');
echo '<p>$encrypted = ' . $encrypted . '<p>';
if (!openssl_private_decrypt($encrypted, $decrypted, $privateKey)) die('Failed to decrypt data');
echo '<p>$decrypted = ' . $decrypted . '<p>';
There you go, Enjoy!