I'm actually working in a small project for myself, is a Web Application that creates Certificate Signing Request also the certificate .pem/.crt and its .key.
The actual problem is that I'm trying to run:
shell_exec(openssl ca -config ../openssl.cnf -in $CSR_FILE -out $CRT_FILE)
And I find the problem that after running this command is asking for my CA passphrase, and later on answering Yes twice to accept the creation of the certificate. I can't figure it out how to make it work. I've been stuck with that for almost three days, neither Google or Stack Overflow has an anwser.
I've tried to run the command and add another shell_exec(passphrase) also, passing passphrase and "y" twice this way.
shell_exec("openssl....","passphrase","y","y")
Thank you very much, i appreciate all help.
You don't have to use shell_exec() for this. You can create slef signed certificate by using openssl_csr_new() PHP function.
It generates a new CSR (Certificate Signing Request) based on the information provided by dn, which represents the Distinguished Name to be used in the certificate.
PHP Code to generate self-signed-certificate
<?php
// For SSL certificates, the commonName is usually the domain name of
// that will be using the certificate, but for S/MIME certificates,
// the commonName will be the name of the individual who will use the certificate.
$dn = array(
"countryName" => "UK",
"stateOrProvinceName" => "Somerset",
"localityName" => "Glastonbury",
"organizationName" => "The Brain Room Limited",
"organizationalUnitName" => "PHP Documentation Team",
"commonName" => "Wez Furlong",
"emailAddress" => "wez#example.com"
);
// Generate a new private (and public) key pair
$privkey = openssl_pkey_new();
// Generate a certificate signing request
$csr = openssl_csr_new($dn, $privkey);
// You will usually want to create a self-signed certificate at this
// point until your CA fulfills your request.
// This creates a self-signed cert that is valid for 365 days
$sscert = openssl_csr_sign($csr, null, $privkey, 365);
// Now you will want to preserve your private key, CSR and self-signed
// cert so that they can be installed into your web server.
openssl_csr_export($csr, $csrout) and var_dump($csrout);
openssl_x509_export($sscert, $certout) and var_dump($certout);
openssl_pkey_export($privkey, $pkeyout, "mypassword") and var_dump($pkeyout);
// Show any errors that occurred here
while (($e = openssl_error_string()) !== false) {
echo $e . "\n";
}
//save certificate and privatekey to file
file_put_contents("certificate.cer", $certout);
file_put_contents("privatekey.pem", $pkeyout);
?>
Related
My project is to issue out certificates to users after they have entered the required information, the issue I run into is after I create the CSR (Certificate Signing Request) based on the info passed in, I try to sign it with CA and the CA key, but it fails and does not give an error.
I wanted to try and make sure that openssl_csr_sign method worked, so first I tried self signing the CSR and that worked, but that would satisfy the project requirement.
I also tried passing in the CA and the CA keys as strings (did not work), I tried sending them in with their path names (did not work), I found this information here
I also removed the passphrase from the CA priv key just to make it as simple as possible
This is the php documentation for openssl_csr_sign link
$dn = array(
"countryName" => $_POST['country'],
"stateOrProvinceName" => $_POST['state'],
"localityName" => $_POST['loc'],
"organizationName" => $_POST['orgName'],
"organizationalUnitName" => $_POST['orgUnit'],
"commonName" => $_POST['name'],
"emailAddress" => $_POST['email']
);
// Generate a new private (and public) key pair
$privkey = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
// Generate a certificate signing request
$csr = openssl_csr_new($dn, $privkey, array('digest_alg' => 'sha256'));
// Generate a certificate authority signed cert, valid for 365 days
$pathToPem = "./PulseSecureCA.crt"; # in my program, they are all absolute path names
$fileGetCert = file_get_contents('./PulseSecureCA.crt');
$fp = fopen($pathToPem, "r");
$CAAuth = fread($fp, 8192);
fclose($fp);
echo "<br/>The Certificate Authority:<br/>".$CAAuth."<br/><br/>";
//$privkeytester = array(file_get_contents("./PulseSecureCA.key"),"abhi");
$pathToCAKey = "./PulseSecureCANoPass.key";
$fileGetKey = file_get_contents('./PulseSecureCANoPass.key');
$fp = fopen("./PulseSecureCANoPass.key", "r");
$CAAuthKey = fread($fp, 8192);
fclose($fp);
echo "<br/>The Certificate Authority Key w/ no pass:<br/>".$CAAuthKey."<br/><br/>";
echo gettype($csr);
if (openssl_csr_sign($csr, $pathToPem, $CAAuthKey, 365, array('digest_alg'=>'sha256')) == FALSE)
echo "breaking here<br/>";
else
echo "signed Cert";
I expect the output to be signed Cert, but I am getting "breaking here" printed on the screen. I tried echo'ing everything to see what was majorly different but I am not sure what I need to do next to get it fixed. OPENSSL.cnf is active and in the right path, and when I run ehco php.info() it says openSSL is enabled. THERE IS NO ERROR PER SAY THAT IS PRINTED, I am completely lost
From what I can see in your code, you have not declared the location of the openssl.cnf file via the 'config' argument. Yes, you can let the application fall back to whatever default file it finds, but from what I've read, letting PHP/Apache fall back to the default openssl.cnf file can sometimes cause unexpected issues.
Please see the answer to this other question to see the minimum required sections in the cnf file: Does OpenSSL really need a path to openssl.conf?
It's possible the issue is with some setting in your cnf file because I've compared your code to mine, for the same type of project, and it looks fine.
I am studying the digital certificates in PKI ( Public Key Infrastructure ). Almost all manuals / pages regarding this give following similar steps.
Get subject identity + subject public key, (AND/OR Encrypted Message hash with subject's private key) and build a certificate.
Sign certificate with CA's private key
At destination, verify certificate with CA's public key
Now I am able to find way in php (using openssl lib) to for 1st and 2nd step which can generate a certificate and sign it ( optionally generate a signature hash and sign it too ) through openssl APIs.
But Issue with third step, Their are no guide line or function call which show how to verify certificate with CA's public key.
If I am missing something ?
Example code I checking is like below
$data = 'my data';
//create new private and public key
$req_key = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
$dn = array(
"countryName" => "IN",
"stateOrProvinceName" => "Delhi",
"organizationName" => "example.net",
"organizationalUnitName" => "Security",
"commonName" => "example.net"
);
$req_csr = openssl_csr_new ($dn, $req_key);
$req_cert = openssl_csr_sign($req_csr, null, $req_key, 365);
openssl_x509_export ($req_cert, $out_cert);
echo $out_cert;
BACKGROUND : I need to implement PKI based data sharing/validating for some application. It would be involve some data entity (data entity would have its on public and private key) encrypted at source side and then send to destination. Then destination decrypt and get clear data. But that whole must involve PKI that means digital signature + digital certificate implementation along with.
This task isn't pretty straightforward in PHP. In fact, PHP isn't good tool for implementing CA stuff. It supports basic PKI operations but that's all. I see three options:
X.509 is just DER encoded ASN.1 structure. You can inspect it with guiDumpASN-ng for example. There are also some ASN.1 libraries in PHP world. Basicaly, the CA signature is inside certificate. If you'll able to extract it, you can then verify digital signature on your own.
http://php.net/manual/en/function.openssl-verify.php#98282
Try to use function like openssl-x509-checkpurpose that should be able to check certificate chain.
Try to use phpseclib - look at Validate X.509 certificates -> validateSignature().
I hope it will help you a little bit.
Do not mess up with implementing certificates validation by yourself but look for an implementation of the CPV (Certification Path Validation) algorithm, which includes all the validations required to be performed in a certification chain, where certificate signature validation is only one of them.
Now, I've been looking for a PHP API to perform CPV but I found none so I resorted to execute the following external OpenSSL command from PHP:
exec("openssl verify -CAfile trusted_root_cas.pem -untrusted intermediate_cas.pem endentity_cert.pem", $output, $return_var);
if ($return_var == 0) {
echo "Certification path validation completed successfully";
} else {
echo "Certification path validation completed with errors";
}
Where all trusted_root_cas.pem, intermediate_cas.pem and endentity_cert.pem could be temporal files created just for the execution of the previous command.
Now, if you want to know what openssl verify does, execute man verify:
The verify command verifies certificate chains.
I am trying to connect to a WSDL that uses WS-Security Certificate Signing over HTTPS.
Only the outgoing messages are signed and it uses Binary Security Token (could not find this specific option in WSO2 but so I am unsure I am using the correct option in the code below).
I have looked at the code in the Samples of the WSO2 WSF/PHP and have joined together the WDSL client example and the Signing example.
Code:
$my_cert = ws_get_cert_from_file("./keys/cert.pem");
$my_key = ws_get_key_from_file("./keys/key.pem");
$sec_array = array("sign"=>TRUE,
"algorithmSuite" => "Basic256Rsa15",
"securityTokenReference" => "EmbeddedToken"); //Is this correct for Binary Security Token?
$policy = new WSPolicy(array("security"=>$sec_array));
$sec_token = new WSSecurityToken(array("privateKey" => $my_key,
"certificate" => $my_cert));
$client = new WSClient(array("wsdl"=>"https://.../Informationservice.WSDL",
"useWSA" => TRUE,
"policy" => $policy,
"securityToken" => $sec_token));
$proxy = $client->getProxy();
$return_val = $proxy->StreetTypes();
Any help would be much appreciated as I haven't been able to find an examples of connecting to a service like this online anywhere. Most services seem to sign with Username and Password rather than Certificates and when looking for WSDL and Certificate Signing I don't find anything at all.
You need to specify the CACert option for https to work with "to" endpoint set to the https endpoint. Also use the non wsdl mode as there are some known issues with wsdl mode.
I'm trying to send S/Mime signed and encrypted emails.
I have this code:
// Sign the message first
openssl_pkcs7_sign("inc/admin/email/body.txt","inc/admin/email/body/enc.txt",
"signing_cert.pem",array("private_key.pem",
"test"),array());
// Get the public key certificate.
$pubkey = file_get_contents("cert.pem");
//encrypt the message, now put in the headers.
openssl_pkcs7_encrypt("signed.txt", "enc.txt", $pubkey,$headers,0,1);
My question is which cert is which? If I use the certs I have (is this ok) the files I have are:
.key
.csr
.crt
and the public .pem.
Which is which?
Generally speaking PEM can be private key, public key and also certificate.
It gepends how did you create/gain certificate.
But in your case, I expect following:
CSR = Certificate signing request, useless for you now
CRT = Certificate
KEY = Private key
PEM = Public key/Certificate
First of all, certificates are not "SSL certificates". This is a misleading term that leads you to wrong use.
Each X.509 certificate has intended use (as defined in Key Usage and Extended Key Usage fields). Certificates issued for securing SSL servers can not be used for S/MIME and vice versa (unless you build some custom infrastructure which doesn't care about Key Usage).
Now, you sign using your certificate and private key, however you encrypt using recipient's certificate (which includes a public key). If you only have one CRT/KEY file pair, it's probably your certificate and your private key accordingly and you can use them for signing. But unless you encrypt the message for yourself (i.e. you are recipient of the encrypted message) encryption using your certificate makes no sense.
I have a task: generate private/public key pairs for banks.
User data like State, City, Company, Name, Email, and some other data should be included. How I can generate those keys with PHP or Shell?
UPDATE 1
I need a private key and cert for a Bank.
PHP offers interface to OpenSSL functions. You need to generate a certificate (the keypair can't include user data), and this is a bit more complicated than generating a keypair. You can generate self-signed certificates (in such certificates Issuer and Subject fields are identical), which is probably what you need.
If you need a CA-signed certificate, than you need to generate a certificate signing request (CSR) and a private key, then send a CSR to the certificate authority that will sign it and send you back the certificate (remember that private key remains on your side, so you need to save it).
Also, google search revealed a good tutorial for you.
Private&public key pairs do not contain identifying information like name and address. Certificates do (and also certificate requests, since those are meant to be turned into certificates).
The openssl command can generate both key pairs and certificate requests, and it can sign certificate requests to produce certificates as well. First, figure out exactly which kinds of objects you need, whether you need to use a central CA to sign certificates, etc... Then you should be able to easily find information on what arguments you need to pass to generate each type of object.
Here is a shell script that I use for generating certificates using openssl.
This is just a test script I wrote, so you might want to set some additional security. Having passwords written somewhere is not a good idea. You might want to run it thoroughly in your test environment or tweak as you like.
Here is what it requires:
A proper CA certificate, its own private key etc, I assume you already have it.
(I generated a self signed one and I would have it in the demoCA folder. Or you can generate using /usr/share/ssl/misc/CA.sh -newca)
Openssl
Text file (cert.input) having Required data {Country, State, City, Company, Org, Common name etc everything in a newline}
Text file (caconfirm.input) for confirmation input (for saying 'yes')
Text file for passwords. (pass.input) I will use MyPassword for all my cert related passwords.
There is only 1 only requirement, the ca private key file should not be password protected. If it is, you can run:
openssl rsa -in demoCA/private/cakey.pem -out
demoCA/private/cakey_nopass.pem
Lets say I stored filename in CERT_FILE_NAME.
In the end you will get a folder with the name you provided (filename) containing:
cert in pem format (filename.pem), cert in crt format (filename.crt), cert in der (binary format, (filename.der)), cert in password protected .p12 format (filename.p12), cert private key password protected (filename_Password.key) and cert private key non password protected. (filename_NoPassword.key)
#!/bin/sh
CERT_FILE_NAME=$1
#Lets generate a typical private key
openssl genrsa -passout pass:MyPassword -des3 -out ${CERT_FILE_NAME}_Password.key 1024
#Now, generate a cert signing request, and recieve the data from cert.input
openssl req -passin pass:MyPassword -new -key ${CERT_FILE_NAME}_Password.key -out ${CERT_FILE_NAME}.csr < cert.input
#Sign the csr with the private key of our CA, and recieve the confirmation from caconfirm.input
openssl ca -in ${CERT_FILE_NAME}.csr -cert demoCA/cacert.pem -keyfile demoCA/private/cakey_nopass.pem -out ${CERT_FILE_NAME}.crt -days 3825 < caconfirm.input
#Export my new cert to a password protected p12 file
openssl pkcs12 -passin pass:MyPassword -passout pass:MyPassword -export -in ${CERT_FILE_NAME}.crt -inkey ${CERT_FILE_NAME}_Password.key -out ${CERT_FILE_NAME}.p12
#(Optional) Export my private key to a plain text private key
openssl rsa -passin file:pass.input -in ${CERT_FILE_NAME}_Password.key -out ${CERT_FILE_NAME}_NOPassword.key
# Output the crt into strict pem format having BEGIN/END lines
grep -A 1000 BEGIN ${CERT_FILE_NAME}.crt > ${CERT_FILE_NAME}.pem
# Convert the pem into der (binary) format
openssl x509 -outform der -in ${CERT_FILE_NAME}.pem -out ${CERT_FILE_NAME}.der
# Create a directory
mkdir ${CERT_FILE_NAME}
# Move all my cert files in the folder
mv ${CERT_FILE_NAME}*.* ${CERT_FILE_NAME}
Now the contents of the text files that we used (every item in newline):
cert.input:
Country
State
CityName
CompanyName
OrgName
CommonName
pass.input:
MyPassword
caconfirm.input:
y
y
Here are PHP codes to generate PRIVATE and PUBLIC KEYS:
===method A) ====
<?php
// generate 2048-bit RSA key
$pk_Generate = openssl_pkey_new(array(
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA
));
// getting private-key
openssl_pkey_export($pk_Generate, $pk_Generate_Private); // we pass 2nd argument as reference
// getting public-key
$pk_Generate_Details = openssl_pkey_get_details($pk_Generate);
$pk_Generate_Public = $pk_Generate_Details['key'];
// free resources
openssl_pkey_free($pk_Generate);
// getting/importing public-key using PEM format
// $pk_Generate_Private now gets into PEM format...
// this is an alternative method compared to above used "public retrieval"
$pk_Import = openssl_pkey_get_private($pk_Generate_Private); // importing
$pk_Import_Details = openssl_pkey_get_details($pk_Import); // same method to get public key, like in previous
$pk_Import_Public = $pk_Import_Details['key'];
openssl_pkey_free($pk_Import); // cleanup
// see output
echo "\r\n\r\n".$pk_Generate_Private."\r\n\r\n".$pk_Generate_Public."\r\n\r\n".$pk_Import_Public ."\r\n\r\n".'Public keys are '.(strcmp($pk_Generate_Public,$pk_Import_Public)?'different':'identical').'.';
?>
====method b) =======
include this [phpsec open-source library][1](with [examples][2]), and then execute:
<?php
include('File/X509.php');
include('Crypt/RSA.php');
// creating private key / x.509 cert for stunnel / website
$priv_Key = new Crypt_RSA();
extract($priv_Key->createKey());
$priv_Key->loadKey($privatekey);
$pub_Key = new Crypt_RSA();
$pub_Key->loadKey($publickey);
$pub_Key->setPublicKey();
$object = new File_X509();
$object->setDNProp('id-at-organizationName', 'phpseclib demo cert');
//$object->removeDNProp('id-at-organizationName');
$object->setPublicKey($pub_Key);
$cert_Issuer = new File_X509();
$cert_Issuer->setPrivateKey($priv_Key);
$cert_Issuer->setDN($object->getDN());
$x_509 = new File_X509();
//$x_509->setStartDate('-1 month'); // default: now
//$x_509->setEndDate('+1 year'); // default: +1 year from now
$result = $x_509->sign($cert_Issuer, $object);
echo "the stunnel.pem contents are as follows:\r\n\r\n".$priv_Key->getPrivateKey()."\r\n\r\n".$x_509->saveX509($result);
?>
What type of private/public are you need? Someone who said you to do this must provide algorythm or type of keys. There is a huge variety of private/public key types, not only RSA.