mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-12-27 03:42:40 +00:00
- make Crypt_RSA use openssl for key generation (if openssl is available) and make it so File_X509 can create CSRs
This commit is contained in:
parent
f0e1b2deec
commit
1417463eba
@ -439,9 +439,9 @@ class Crypt_RSA {
|
||||
{
|
||||
if ( !defined('CRYPT_RSA_MODE') ) {
|
||||
switch (true) {
|
||||
//case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
|
||||
// define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
|
||||
// break;
|
||||
case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
|
||||
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
|
||||
break;
|
||||
default:
|
||||
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
|
||||
}
|
||||
@ -477,9 +477,28 @@ class Crypt_RSA {
|
||||
*/
|
||||
function createKey($bits = 1024, $timeout = false, $partial = array())
|
||||
{
|
||||
if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) {
|
||||
$rsa = openssl_pkey_new(array('private_key_bits' => $bits));
|
||||
openssl_pkey_export($rsa, $privatekey);
|
||||
if (!defined('CRYPT_RSA_EXPONENT')) {
|
||||
// http://en.wikipedia.org/wiki/65537_%28number%29
|
||||
define('CRYPT_RSA_EXPONENT', '65537');
|
||||
}
|
||||
// per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
|
||||
// than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
|
||||
// to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
|
||||
// CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
|
||||
// CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
|
||||
// generation when there's a chance neither gmp nor OpenSSL are installed)
|
||||
if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
|
||||
define('CRYPT_RSA_SMALLEST_PRIME', 4096);
|
||||
}
|
||||
|
||||
// OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
|
||||
if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
|
||||
$rsa = openssl_pkey_new(array(
|
||||
'private_key_bits' => $bits,
|
||||
'config' => dirname(__FILE__) . '/../openssl.cnf'
|
||||
));
|
||||
|
||||
openssl_pkey_export($rsa, $privatekey, NULL, array('config' => dirname(__FILE__) . '/../openssl.cnf'));
|
||||
$publickey = openssl_pkey_get_details($rsa);
|
||||
$publickey = $publickey['key'];
|
||||
|
||||
@ -488,6 +507,9 @@ class Crypt_RSA {
|
||||
$publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
|
||||
}
|
||||
|
||||
// clear the buffer of error strings stemming from a minimalistic openssl.cnf
|
||||
while (openssl_error_string() !== false);
|
||||
|
||||
return array(
|
||||
'privatekey' => $privatekey,
|
||||
'publickey' => $publickey,
|
||||
@ -497,22 +519,12 @@ class Crypt_RSA {
|
||||
|
||||
static $e;
|
||||
if (!isset($e)) {
|
||||
if (!defined('CRYPT_RSA_EXPONENT')) {
|
||||
// http://en.wikipedia.org/wiki/65537_%28number%29
|
||||
define('CRYPT_RSA_EXPONENT', '65537');
|
||||
}
|
||||
// per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
|
||||
// than 256 bits.
|
||||
if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
|
||||
define('CRYPT_RSA_SMALLEST_PRIME', 4096);
|
||||
}
|
||||
|
||||
$e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
|
||||
}
|
||||
|
||||
extract($this->_generateMinMax($bits));
|
||||
$absoluteMin = $min;
|
||||
$temp = $bits >> 1;
|
||||
$temp = $bits >> 1; // divide by two to see how many bits P and Q would be
|
||||
if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
|
||||
$num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
|
||||
$temp = CRYPT_RSA_SMALLEST_PRIME;
|
||||
|
@ -1269,7 +1269,7 @@ class File_X509 {
|
||||
/**
|
||||
* Save X.509 certificate
|
||||
*
|
||||
* @param optional Array $cert
|
||||
* @param Array $cert
|
||||
* @access public
|
||||
* @return String
|
||||
*/
|
||||
@ -2059,6 +2059,7 @@ class File_X509 {
|
||||
$orig = $csr = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $csr) ? base64_decode($csr) : false;
|
||||
|
||||
if ($csr === false) {
|
||||
$this->currentCert = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2066,6 +2067,7 @@ class File_X509 {
|
||||
$decoded = $asn1->decodeBER($csr);
|
||||
$csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
|
||||
if (!isset($csr) || $csr === false) {
|
||||
$this->currentCert = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2095,6 +2097,40 @@ class File_X509 {
|
||||
return $csr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save CSR request
|
||||
*
|
||||
* @param Array $csr
|
||||
* @access public
|
||||
* @return String
|
||||
*/
|
||||
function saveCSR($csr)
|
||||
{
|
||||
if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm']) {
|
||||
case 'rsaEncryption':
|
||||
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] =
|
||||
base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
|
||||
}
|
||||
|
||||
$asn1 = new File_ASN1();
|
||||
|
||||
$asn1->loadOIDs($this->oids);
|
||||
|
||||
$filters = array();
|
||||
$filters['certificationRequestInfo']['subject']['rdnSequence']['value'] =
|
||||
array('type' => FILE_ASN1_TYPE_UTF8_STRING);
|
||||
|
||||
$asn1->loadFilters($filters);
|
||||
|
||||
$csr = $asn1->encodeDER($csr, $this->CertificationRequest);
|
||||
|
||||
return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr)) . '-----END CERTIFICATE REQUEST-----';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign an X.509 certificate
|
||||
*
|
||||
@ -2102,8 +2138,8 @@ class File_X509 {
|
||||
* $subject can be either an existing X.509 cert (if you want to resign it),
|
||||
* a CSR or something with the DN and public key explicitly set.
|
||||
*
|
||||
* @param Crypt_X509 $issuer
|
||||
* @param Crypt_X509 $subject
|
||||
* @param File_X509 $issuer
|
||||
* @param File_X509 $subject
|
||||
* @param String $signatureAlgorithm optional
|
||||
* @access public
|
||||
* @return Mixed
|
||||
@ -2122,10 +2158,10 @@ class File_X509 {
|
||||
$signatureSubject = $this->signatureSubject;
|
||||
|
||||
if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
|
||||
$this->currentCert = $subject->currentCert;
|
||||
$this->currentCert['tbsCertificate']['signature']['algorithm'] =
|
||||
$this->currentCert['signatureAlgorithm']['algorithm'] =
|
||||
$signatureAlgorithm;
|
||||
$this->currentCert = $subject->currentCert;
|
||||
if (!empty($this->startDate)) {
|
||||
$this->currentCert['tbsCertificate']['validity']['notBefore']['generalTime'] = $this->startDate;
|
||||
unset($this->currentCert['tbsCertificate']['validity']['notBefore']['utcTime']);
|
||||
@ -2258,11 +2294,70 @@ class File_X509 {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a CSR
|
||||
*
|
||||
* @access public
|
||||
* @return Mixed
|
||||
*/
|
||||
function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
|
||||
{
|
||||
if (!is_object($this->privateKey) || empty($this->dn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$origPublicKey = $this->publicKey;
|
||||
$class = get_class($this->privateKey);
|
||||
$this->publicKey = new $class();
|
||||
$this->publicKey->loadKey($this->privateKey->getPublicKey());
|
||||
$this->publicKey->setPublicKey();
|
||||
if (!($publicKey = $this->_formatSubjectPublicKey())) {
|
||||
return false;
|
||||
}
|
||||
$this->publicKey = $origPublicKey;
|
||||
|
||||
$currentCert = $this->currentCert;
|
||||
$signatureSubject = $this->signatureSubject;
|
||||
|
||||
if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
|
||||
$this->currentCert['signatureAlgorithm']['algorithm'] =
|
||||
$signatureAlgorithm;
|
||||
if (!empty($this->dn)) {
|
||||
$this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
|
||||
}
|
||||
$this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
|
||||
} else {
|
||||
$this->currentCert = array(
|
||||
'certificationRequestInfo' =>
|
||||
array(
|
||||
'version' => 'v1',
|
||||
'subject' => $this->dn,
|
||||
'subjectPKInfo' => $publicKey
|
||||
),
|
||||
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
|
||||
'signature' => false // this is going to be overwritten later
|
||||
);
|
||||
}
|
||||
|
||||
// resync $this->signatureSubject
|
||||
// save $certificationRequestInfo in case there are any File_ASN1_Element objects in it
|
||||
$certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
|
||||
$this->loadCSR($this->saveCSR($this->currentCert));
|
||||
|
||||
$result = $this->_sign($this->privateKey, $signatureAlgorithm);
|
||||
$result['certificationRequestInfo'] = $certificationRequestInfo;
|
||||
|
||||
$this->currentCert = $currentCert;
|
||||
$this->signatureSubject = $signatureSubject;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* X.509 certificate signing helper function.
|
||||
*
|
||||
* @param Object $key
|
||||
* @param Crypt_X509 $subject
|
||||
* @param File_X509 $subject
|
||||
* @param String $signatureAlgorithm
|
||||
* @access public
|
||||
* @return Mixed
|
||||
|
6
phpseclib/openssl.cnf
Normal file
6
phpseclib/openssl.cnf
Normal file
@ -0,0 +1,6 @@
|
||||
# minimalist openssl.cnf file for use with phpseclib
|
||||
|
||||
HOME = .
|
||||
RANDFILE = $ENV::HOME/.rnd
|
||||
|
||||
[ v3_ca ]
|
Loading…
Reference in New Issue
Block a user