Add extended keyusage extensions on generated certificatees with phpseclib - php

I can add keyusage with phpseclib using this code:
$x509->setExtension('id-ce-keyUsage', array('digitalSignature', 'keyEncipherment'));
Is possible to also set extended key usage? Any docs on that?

$x509->setExtension('id-ce-extKeyUsage', array('id-kp-serverAuth', 'id-kp-clientAuth'));
Full example:
<?php
include('File/X509.php');
include('Crypt/RSA.php');
// create private key / x.509 cert for stunnel / website
$privKey = new Crypt_RSA();
extract($privKey->createKey());
$privKey->loadKey($privatekey);
$pubKey = new Crypt_RSA();
$pubKey->loadKey($publickey);
$pubKey->setPublicKey();
$subject = new File_X509();
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
$subject->setPublicKey($pubKey);
$issuer = new File_X509();
$issuer->setPrivateKey($privKey);
$issuer->setDN($subject->getDN());
$x509 = new File_X509();
$x509->loadX509($x509->saveX509($x509->sign($issuer, $subject)));
$x509->setExtension('id-ce-keyUsage', array('digitalSignature', 'keyEncipherment'));
$x509->setExtension('id-ce-extKeyUsage', array('id-kp-serverAuth', 'id-kp-clientAuth'));
$result = $x509->sign($issuer, $x509);
echo "the stunnel.pem contents are as follows:\r\n\r\n";
echo $privKey->getPrivateKey();
echo "\r\n";
echo $x509->saveX509($result);
echo "\r\n";
I can't say I like it how you have to re-sign a cert to get this effect but whatever.

Related

phpseclib: Validating signed data using certificate

I do have a private.pem and public.crt. my goal is to signed using private.pem and to verify its signature using public.crt. How do I achieve this by using phpseclib ?
$data = 'test';
$rsa = new RSA();
$privatekey = file_get_contents(storage_path('app/private.pem'));
$rsa->loadKey($privatekey);
$signed = $rsa->sign($data);
$publickey = file_get_contents(storage_path('app/public.crt'));
$rsa->loadKey($publickey);
return $rsa->verify($data, $signed) ? 'verified' : 'unverified';
got my answer here:
<?php
$data = 'test';
$rsa = new RSA();
$x509 = new X509();
$privatekey = file_get_contents(storage_path('app/private.pem'));
$rsa->loadKey($privatekey);
$signed = $rsa->sign($data);
$publickey = file_get_contents(storage_path('app/public.crt'));
$x509->loadX509($publickey);
$rsa = $x509->getPublicKey();
return $rsa->verify($data, $signed) ? 'verified' : 'unverified';

Generated certificate from phpseclib is valid but not recognised by browsers after KEYGEN submit

I'm trying to create a simple PKI infrastucture for internal use, and I want to use the html <keygen> tag.
I know this tag sends an SPKAK to server, wich will have to sign it. Since I can't use exec to launch openssl, and have php 5.5, the only way to process SPKAK is with phpseclib.
This is my code:
<?PHP
if(isset($_POST['key'])){
header('Content-type: application/x-x509-user-cert');
header('Content-disposition: attachment; filename=user.crt');
include('File/X509.php');
$capem = file_get_contents('root-ca.crt');
$subject = new File_X509();
$subject->loadCA($capem);
$subject->loadSPKAC($_POST['key']);
$subject->setDN('CN=Username');
$issuer = new File_X509();
$issuer->loadX509($capem);
$cakey = new Crypt_RSA();
$cakey->setPassword('SECRETPASSWORD');
$cakey->loadKey(file_get_contents('root-ca.key'));
$issuer->setPrivateKey($cakey);
$x509 = new File_X509();
$cert = $x509->sign($issuer, $subject);
$x509->loadX509($cert);
$x509->setExtension('id-ce-keyUsage', array('digitalSignature', 'keyEncipherment'));
$x509->setStartDate('-1 day');
$x509->setEndDate('+ 3 year');
$x509->setSerialNumber('1235', 10);
$cert = $x509->sign($issuer, $x509);
echo $x509->saveX509($cert);
}else{
?>
<form method="POST">
<keygen name="key" keytype="RSA" challenge="ucert">
<button>SEND</button>
</form>
<?PHP
}
?>
The strange thing is that the generated certificate is valid (windows recognises it) but the browser (both Chrome and Firefox in my testings) doesn't recognise it, giving error 201 INVALID CERT, so it's not associated with the private key stored on browser.
What's the correct way to do this?
<?php
include('File/X509.php');
include('Crypt/RSA.php');
// create private key / x.509 cert for stunnel / website
$privKey = new Crypt_RSA();
extract($privKey->createKey());
$privKey->loadKey($privatekey);
$pubKey = new Crypt_RSA();
$pubKey->loadKey($publickey);
$pubKey->setPublicKey();
$subject = new File_X509();
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
$subject->setPublicKey($pubKey);
$issuer = new File_X509();
$issuer->setPrivateKey($privKey);
$issuer->setDN($subject->getDN());
$x509 = new File_X509();
$x509->loadX509($x509->saveX509($x509->sign($issuer, $subject)));
$x509->setExtension('id-ce-keyUsage', array('digitalSignature', 'keyEncipherment', 'dataEncipherment'));
$x509->setExtension('id-ce-extKeyUsage', array('id-kp-serverAuth', 'id-kp-clientAuth'));
$result = $x509->sign($issuer, $x509);
file_put_contents('key.pem', $privKey->getPrivateKey() . "\r\n" . $x509->saveX509($result));
exec('openssl pkcs12 -export -out file.pfx -in key.pem');
I was able to import the resultant file.pfx file into Google Chrome. It shows up now as a "Personal Certificate".

How do I set extKeyUsage with phpseclib?

I want to add the SSL Server and SSL Client flags to a cert that I am signing with phpseclib, how would I go about this? I found the setExtension function, but I dont know how to use it. Any help is appreciated, thanks.
I have tried the following and it doesnt work (mostly from the phpseclib example):
// create private key for CA cert
$CAPrivKey = new Crypt_RSA();
extract($CAPrivKey->createKey());
$CAPrivKey->loadKey($privatekey);
$pubKey = new Crypt_RSA();
$pubKey->loadKey($publickey);
$pubKey->setPublicKey();
echo "the private key for the CA cert (can be discarded):\r\n\r\n";
echo $privatekey;
echo "\r\n\r\n";
// create a self-signed cert that'll serve as the CA
$subject = new File_X509();
$subject->setPublicKey($pubKey);
$subject->setDNProp('id-at-organizationName', 'phpseclib demo CA');
$issuer = new File_X509();
$issuer->setPrivateKey($CAPrivKey);
$issuer->setDN($CASubject = $subject->getDN());
$x509 = new File_X509();
$x509->setStartDate('-1 month');
$x509->setEndDate('+1 year');
$x509->setSerialNumber(chr(1));
$x509->makeCA();
$result = $x509->sign($issuer, $subject);
echo "the CA cert to be imported into the browser is as follows:\r\n\r\n";
echo $x509->saveX509($result);
echo "\r\n\r\n";
// create private key / x.509 cert for stunnel / website
$privKey = new Crypt_RSA();
extract($privKey->createKey());
$privKey->loadKey($privatekey);
$pubKey = new Crypt_RSA();
$pubKey->loadKey($publickey);
$pubKey->setPublicKey();
$subject = new File_X509();
$subject->setPublicKey($pubKey);
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
$subject->setDomain('www.google.com');
$issuer = new File_X509();
$issuer->setPrivateKey($CAPrivKey);
$issuer->setDN($CASubject);
$x509 = new File_X509();
$x509->setStartDate('-1 month');
$x509->setEndDate('+1 year');
$x509->setSerialNumber(chr(1));
$x509->setExtension('id-ce-extKeyUsage', array('id-kp-serverAuth', 'id-kp-clientAuth'));
$result = $x509->sign($issuer, $subject);
echo "the stunnel.pem contents are as follows:\r\n\r\n";
echo $privKey->getPrivateKey();
echo "\r\n";
echo $x509->saveX509($result);
echo "\r\n";
What you'd have to currently do is first create the X.509 cert, add the extensions to the X.509 cert after it's been created and then re-sign it. eg.
After $result = $x509->sign($issuer, $subject); do this:
$x509->loadX509($result);
$x509->setExtension('id-ce-extKeyUsage', array('id-kp-serverAuth', 'id-kp-clientAuth'));
$result = $x509->sign($issuer, $x509);
ie. you sign the cert, load it, set the extension, and then resign it.
Not an elegant solution unfortunately. It's my understanding that the API will, at some point, be updated to let you update extensions without having to first have the cert but that has yet to happen.

Why is phpseclib producing incompatible certs?

Why is it that when I try to use a certificate/key pair generated from phpseclib, the OpenSSL server code errors out? Certs/Keys generated from OpenSSL work fine. How do I fix this?
Certificate/Key Generation taken straight from phpseclib documentation:
<?php
include('File/X509.php');
include('Crypt/RSA.php');
// create private key / x.509 cert for stunnel / website
$privKey = new Crypt_RSA();
extract($privKey->createKey());
$privKey->loadKey($privatekey);
$pubKey = new Crypt_RSA();
$pubKey->loadKey($publickey);
$pubKey->setPublicKey();
$subject = new File_X509();
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
//$subject->removeDNProp('id-at-organizationName');
$subject->setPublicKey($pubKey);
$issuer = new File_X509();
$issuer->setPrivateKey($privKey);
$issuer->setDN($subject->getDN());
$x509 = new File_X509();
//$x509->setStartDate('-1 month'); // default: now
//$x509->setEndDate('+1 year'); // default: +1 year
$result = $x509->sign($issuer, $subject);
echo "the stunnel.pem contents are as follows:\r\n\r\n";
echo $privKey->getPrivateKey();
echo "\r\n";
echo $x509->saveX509($result);
echo "\r\n";
?>
Phpseclib requires you to call $x509->setSerialNumber("0") otherwise it will produce an invalid cert.

Openssl return status in cmd

I am using openssl command for creating certificate using PHP.I am using exec.When I give exec the command ,the return status is 1,I echoed whatever i insert in exec(OpenSSL statement) and try it through cmd and it works fine (generate certificates) but it doesn't work when I run it through PHP exec. Anyone who can help me for this.
Thanks
Maybe you'd have an easier time with phpseclib, a pure PHP X.509 implementation? Example of how to create a self-signed cert:
<?php
include('File/X509.php');
include('Crypt/RSA.php');
// create private key / x.509 cert for stunnel / website
$privKey = new Crypt_RSA();
extract($privKey->createKey());
$privKey->loadKey($privatekey);
$pubKey = new Crypt_RSA();
$pubKey->loadKey($publickey);
$pubKey->setPublicKey();
$subject = new File_X509();
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
//$subject->removeDNProp('id-at-organizationName');
$subject->setPublicKey($pubKey);
$issuer = new File_X509();
$issuer->setPrivateKey($privKey);
$issuer->setDN($subject->getDN());
$x509 = new File_X509();
//$x509->setStartDate('-1 month'); // default: now
//$x509->setEndDate('+1 year'); // default: +1 year
$result = $x509->sign($issuer, $subject);
echo "the stunnel.pem contents are as follows:\r\n\r\n";
echo $privKey->getPrivateKey();
echo "\r\n";
echo $x509->saveX509($result);
echo "\r\n";
?>

Categories