How to encrypt data with a public key using RSA method from phpseclib3? - laravel-9

I want to encrpypt some data with phpseclib3 with a public key. The example I found on the RSA.php file doesn't showing how to do encryption with a given public key.
here is the code example on the rsa.php
* <?php
* include 'vendor/autoload.php';
*
* $private = \phpseclib3\Crypt\RSA::createKey();
* $public = $private->getPublicKey();
*
* $plaintext = 'terrafrost';
*
* $ciphertext = $public->encrypt($plaintext);
*
* echo $private->decrypt($ciphertext);
* ?>
But, I want to use my key to do the encryption.

In my projects I'm loading the private and public key from a String but usually you will load the keys from a file (load a textfile in a variable should be no big problem :-).
My example is using OAES SHA-256 as encryption scheme:
function rsaEncryptionOaepSha256($publicKey, $plaintext) {
$rsa = PublicKeyLoader::load($publicKey)
->withHash('sha256')
->withMGFHash('sha256');
return $rsa->encrypt($plaintext);
}
function rsaDecryptionOaepSha256($privateKey, $ciphertext) {
$rsa = PublicKeyLoader::load($privateKey)
->withHash('sha256')
->withMGFHash('sha256');
return $rsa->decrypt($ciphertext);
}
function loadRsaPrivateKeyPem() {
// this is a sample key - don't worry !
return '
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDwSZYlRn86zPi9
...
3PIW4/CddNs8mCSBOqTnoaxh
-----END PRIVATE KEY-----
';
}
function loadRsaPublicKeyPem() {
// this is a sample key - don't worry !
return '
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8EmWJUZ/Osz4vXtUU2S+
...
QwIDAQAB
-----END PUBLIC KEY-----
';
}

Related

(node:13672) UnhandledPromiseRejectionWarning: Error: error:0909006C:PEM routines:get_name:no start line

I have done research into this error and it seems as though so far nothing is working for me. I am using Node.js and the crypto library. My Private key is stored in a dotenv file like below:
.env file
PRIVATE_KEY = -----BEGIN RSA PRIVATE KEY-----
ezfvDUlrPehGYvlmQq3ReTk8EiO8N0RDvsJqerZJ91Lb6UBGlOyuv/SaxDxwxx/g
....more lines...
5SRwCCIaByIwAw0HkQx+XnBqW8II2TgTb9MMBQht/Cu5WZKFroagGQO5cgyilQg4
-----END RSA PRIVATE KEY-----
index.ts
const WM_KEY_PRIVATE = process.env.WM_KEY_PRIVATE;
function createSignature(reqHeaders: SecurityHeaders) {
const signer = createSign('RSA-SHA256');
const payload = generateSignatureMap(reqHeaders);
console.log("payload:", payload);
signer.update(payload);
signer.end();
return signer.sign(WM_KEY_PRIVATE, 'base64');
}
function generateSignatureMap(reqHeaders: SecurityHeaders) {
let keys: string[] = Object.keys(reqHeaders).sort();
let vals: string[] = [];
for(let k of keys) {
vals.push(reqHeaders[k].toString().trim());
}
return vals.join('\n') + '\n';
// let keys = reqHeaders.toString()
// return keys
}
Can anyone point me in the right direction to get rid of this error? Should I not use .env to store the key? I have read where keys in this format are difficult to load from .env files, but I have not come across a real solid solution for this. I have tried making it all one line too. Any help in understanding this will be appreciated. Thank you.
I was having the same error -- error:0909006C:PEM routines:get_name:no start line -- using libcrypto (OpenSSL) in C. So a different environment but perhaps this could be useful for someone else.
In my case I had the certificate in a string and conversion to an X509 type always failed. But it worked when the certificate was read from file.
The problem was the lack of \n as #dave_thompson_085 suggested in a comment to the OP's question.
Doesn't work: no \n
static const char *C1 = "-----BEGIN CERTIFICATE-----"
"MIIEoTCCAwmgAwIBAgIJANEHdl0yo7CWMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV"
(...)
"tQAVo+yVgLgV2Hws73Fc0o3wC78qPEA+v2aRs/Be3ZFDgDyghc/1fgU+7C+P6kbq"
"d4poyb6IW8KCJbxfMJvkordNOgOUUxndPHEi/tb/U7uLjLOgPA=="
"-----END CERTIFICATE-----";
Fixed version
static const char *C1 = "-----BEGIN CERTIFICATE-----\n"
"MIIEoTCCAwmgAwIBAgIJANEHdl0yo7CWMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV\n"
(...)
"tQAVo+yVgLgV2Hws73Fc0o3wC78qPEA+v2aRs/Be3ZFDgDyghc/1fgU+7C+P6kbq\n"
"d4poyb6IW8KCJbxfMJvkordNOgOUUxndPHEi/tb/U7uLjLOgPA==\n"
"-----END CERTIFICATE-----\n";
Note the \n at the end of each line.

Validate EC SHA 256 signature in .net without bouncy castle

I am implementing Apple's App Attestation service.
As part of the process, i receive a EC key and a signature.
Sample key:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEd34IR9wYL76jLyZ148O/hjXo9iaF
z/q/xEMXCwYPy6yxbxYzWDZPegG4FH+snXaXQPYD6QIzZNY/kcMjIGtUTg==
-----END PUBLIC KEY-----
Sample signature:
MEUCIQDXR/22YAi90PUdKrtTHwigrDxWFoiCqPLB/Of1bZPCKQIgNLxFAeUU2x+FSWfhRGX0SOKUIDxPRoigsCHpJxgGXXU=
Sample sha256 hash:
S3i6LAEzew5SDjQbq59/FraEAvGDg9y7fRIfbnhHPf4=
If i put this into a couple of txt files like so:
System.IO.File.WriteAllBytes("/wherever/sig", Convert.FromBase64String(sampleSignature));
System.IO.File.WriteAllBytes("/wherever/hash", Convert.FromBase64String(sampleSha256Hash));
Then i can validate the signature with Openssl like so
openssl dgst -sha256 -verify sampleKey.pem -signature /wherever/sig /wherever/hash
(the above outputs)
Verified OK
I can verify the signature using Bouncy Castle like so:
var bouncyCert = DotNetUtilities.FromX509Certificate(certificate);
var bouncyPk = (ECPublicKeyParameters)bouncyCert.GetPublicKey();
var verifier = SignerUtilities.GetSigner("SHA-256withECDSA");
verifier.Init(false, bouncyPk);
verifier.BlockUpdate(sha256HashByteArray, 0, sha256HashByteArray.Length);
var valid = verifier.VerifySignature(signature); // Happy days, this is true
Since i don't want to share my whole certificate here, the same sample may be achieved as follows:
// these are the values from the sample key shared at the start of the post
// as returned by BC. Note that .Net's Y byte array is completely different.
Org.BouncyCastle.Math.BigInteger x = new Org.BouncyCastle.Math.BigInteger(Convert.FromBase64String("d34IR9wYL76jLyZ148O/hjXo9iaFz/q/xEMXCwYPy6w="));
Org.BouncyCastle.Math.BigInteger y = new Org.BouncyCastle.Math.BigInteger(Convert.FromBase64String("ALFvFjNYNk96AbgUf6yddpdA9gPpAjNk1j+RwyMga1RO"));
X9ECParameters nistParams = NistNamedCurves.GetByName("P-256");
ECDomainParameters domainParameters = new ECDomainParameters(nistParams.Curve, nistParams.G, nistParams.N, nistParams.H, nistParams.GetSeed());
var G = nistParams.G;
Org.BouncyCastle.Math.EC.ECCurve curve = nistParams.Curve;
Org.BouncyCastle.Math.EC.ECPoint q = curve.CreatePoint(x, y);
ECPublicKeyParameters pubkeyParam = new ECPublicKeyParameters(q, domainParameters);
var verifier = SignerUtilities.GetSigner("SHA-256withECDSA");
verifier.Init(false, pubkeyParam);
verifier.BlockUpdate(sha256HashByteArray, 0, sha256HashByteArray.Length);
var valid = verifier.VerifySignature(signature); // again, happy days.
However, i really want to avoid using bouncy castle.
So i am trying to use ECDsa available in .net core:
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
var certificate = new X509Certificate2(cert);
var publicKey = certificate.GetECDsaPublicKey();
var valid = publicKey.VerifyHash(sha256HashByteArray, signature); // FALSE :(
if you want to try to run the above here's the sample that creates the keys without the whole certificate:
using System.Security.Cryptography;
var ecParams = new ECParameters();
ecParams.Curve = ECCurve.CreateFromValue("1.2.840.10045.3.1.7");
ecParams.Q.X = Convert.FromBase64String("d34IR9wYL76jLyZ148O/hjXo9iaFz/q/xEMXCwYPy6w=");
// I KNOW that this is different from BC sample - i got each respective values from
// certificates in respective libraries, and it seems the way they format the coordinates
// are different.
ecParams.Q.Y = Convert.FromBase64String("sW8WM1g2T3oBuBR/rJ12l0D2A+kCM2TWP5HDIyBrVE4=");
var ecDsa = ECDsa.Create(ecParams);
var isValid = ecDsa.VerifyHash(nonce, signature); // FALSE :(
I tried using VerifyData() instead and feeding raw data and HashAlgorithmName.SHA256 with no luck.
I found a response here (https://stackoverflow.com/a/49449863/2057955) that seems to suggest that .net expects the signature as r,s concatenation, so i pulled them out of the DER sequence that i get back from my device (see sample signature) however that had no luck at all, i just can't get that 'true' back.
Question: how can i verify this EC signature using .Net Core on LINUX/MacOs (so unable to use ECDsaCng class)?
SignerUtilities.GetSigner() hashes implicitly, i.e. sha256HashByteArray is hashed again. Therefore instead of ECDsa#VerifyHash() (does not hash implicitly) the method ECDsa#VerifyData() (hashes implicitly) must be used.
Also, SignerUtilities.GetSigner() returns a signature in ASN.1 format, and ECDsa#VerifyData() expects a signature in r|s format (as you already figured out).
If both are taken into account, the verification is successful:
byte[] publicKey = Convert.FromBase64String("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEd34IR9wYL76jLyZ148O/hjXo9iaFz/q/xEMXCwYPy6yxbxYzWDZPegG4FH+snXaXQPYD6QIzZNY/kcMjIGtUTg==");
byte[] sha256HashByteArray = Convert.FromBase64String("S3i6LAEzew5SDjQbq59/FraEAvGDg9y7fRIfbnhHPf4=");
byte[] signatureRS = Convert.FromBase64String("10f9tmAIvdD1HSq7Ux8IoKw8VhaIgqjywfzn9W2Twik0vEUB5RTbH4VJZ+FEZfRI4pQgPE9GiKCwIeknGAZddQ==");
var ecDsa = ECDsa.Create();
ecDsa.ImportSubjectPublicKeyInfo(publicKey, out _);
var isValid = ecDsa.VerifyData(sha256HashByteArray, signatureRS, HashAlgorithmName.SHA256);
Console.WriteLine(isValid); // True
Regarding the signature formats:
The posted signature in ASN.1 format
MEUCIQDXR/22YAi90PUdKrtTHwigrDxWFoiCqPLB/Of1bZPCKQIgNLxFAeUU2x+FSWfhRGX0SOKUIDxPRoigsCHpJxgGXXU=
is hex encoded
3045022100d747fdb66008bdd0f51d2abb531f08a0ac3c56168882a8f2c1fce7f56d93c229022034bc4501e514db1f854967e14465f448e294203c4f4688a0b021e92718065d75
From this, the signature in r|s format can be derived as (s. here)
d747fdb66008bdd0f51d2abb531f08a0ac3c56168882a8f2c1fce7f56d93c22934bc4501e514db1f854967e14465f448e294203c4f4688a0b021e92718065d75
or Base64 encoded:
10f9tmAIvdD1HSq7Ux8IoKw8VhaIgqjywfzn9W2Twik0vEUB5RTbH4VJZ+FEZfRI4pQgPE9GiKCwIeknGAZddQ==

JWT public key vs private key signature validation -- what is the difference?

I am using this library, node-jwks-rsa, to fetch JWT keys from my auth0 jwks.json file in order to verify that the id_token my application retrieves after authentication is actually coming from my auth provider.
Under the hood it uses this method to build a public key PEM
export function certToPEM(cert) {
cert = cert.match(/.{1,64}/g).join('\n');
cert = `-----BEGIN CERTIFICATE-----\n${cert}\n-----END CERTIFICATE-----\n`;
return cert;
}
(Using the x50c as argument from the .jwks file).
which I then use in combination with jsonwebtoken to verify that the JWT(id_token) is valid.
How is this method of verification different from generating a private key(RSA) from the modulus and exponent of the jwks.json file and using it for verification instead? (as example see this library)
Additionally here is function as demonstration that generates a PEM from a mod and exponent (taken from http://stackoverflow.com/questions/18835132/xml-to-pem-in-node-js)
export function rsaPublicKeyToPEM(modulusB64, exponentB64) {
const modulus = new Buffer(modulusB64, 'base64');
const exponent = new Buffer(exponentB64, 'base64');
const modulusHex = prepadSigned(modulus.toString('hex'));
const exponentHex = prepadSigned(exponent.toString('hex'));
const modlen = modulusHex.length / 2;
const explen = exponentHex.length / 2;
const encodedModlen = encodeLengthHex(modlen);
const encodedExplen = encodeLengthHex(explen);
const encodedPubkey = '30' +
encodeLengthHex(modlen + explen + encodedModlen.length / 2 + encodedExplen.length / 2 + 2) +
'02' + encodedModlen + modulusHex +
'02' + encodedExplen + exponentHex;
const der = new Buffer(encodedPubkey, 'hex')
.toString('base64');
let pem = `-----BEGIN RSA PUBLIC KEY-----\n`;
pem += `${der.match(/.{1,64}/g).join('\n')}`;
pem += `\n-----END RSA PUBLIC KEY-----\n`;
return pem;
};
The aforementioned jsonwebtoken library can verify a JWT using either -- but why? If both of these verification methods can validate a JWT signature why do they both exist? What are the tradeoffs between them? Is one more secure than the other? Which should I use to verify most fully?
Using a RSA assymetric key pair, the JWT is signed with the private key and verified with the public. You can not verify a digital signature with the private key
Modulus and exponent are the components of the public key and you can use it to build the public key in PEM format, which is a base64 representation of the public key (modulus and exponent) encoded in DER binary format. You can use PEM, DER or modulus and exponent because the contain the same information
But anybody can't build the private key with modulus and exponent. He would need the private RSA elements, which must be kept secret so that no one can sign for you.

ECC public and private keys setters

I need to test ECC verification with given public and private keys. I found methods for random keys generation but there are no setters for specific public/private keys. How to set public/private keys as byte array?
byte[] privateKeyBytes = new byte[]{(byte)0x24, (byte)0xF4, (byte)0x36, (byte)0x16, (byte)0xD0, (byte)0x96, (byte)0x12, (byte)0x63, (byte)0x90, (byte)0x2E, (byte)0x51, (byte)0xF6, (byte)0x87, (byte)0x55, (byte)0xAB, (byte)0xCB, (byte)0x5D, (byte)0xAC, (byte)0x56, (byte)0x1A, (byte)0xA5, (byte)0xFA, (byte)0x55, (byte)0xDB};
byte[] publicKeyBytes = new byte[]{(byte)0x71, (byte)0x0B, (byte)0xCD, (byte)0xF8, (byte)0xEE, (byte)0x7F, (byte)0x36, (byte)0x32, (byte)0xF4, (byte)0x3E, (byte)0x8B, (byte)0x20, (byte)0x54, (byte)0xF7, (byte)0x84, (byte)0x26, (byte)0x4E, (byte)0x96, (byte)0xD9, (byte)0xBA, (byte)0x0F, (byte)0x82, (byte)0x84, (byte)0x2D, (byte)0xC1, (byte)0x31, (byte)0xE0, (byte)0xBF, (byte)0x9F, (byte)0x60, (byte)0x5F, (byte)0xAE, (byte)0x3A, (byte)0xA1, (byte)0x43, (byte)0x50, (byte)0x88, (byte)0x87, (byte)0xFE, (byte)0x49, (byte)0x6C, (byte)0x1F, (byte)0xF6, (byte)0x82, (byte)0x73, (byte)0xD8, (byte)0x77, (byte)0x8F};
KeyPair pair = g.generateKeyPair();
PublicKey pubKey = pair.getPublic();
PrivateKey prikey = pair.getPrivate();
Public and Private Keys can't be set, because they should be generated.
According to this, you won't be able to set it.
Normally you are able to encode a message and put the public key into the encoding method. Mabye you have an "ImportParameters"-Function like in C#, where you can import a "Key" into the chosen algorithm like RSA.
Edit:
According to THIS answer, you can import like this.
I would suggest you generate the keys, store them using a serialisation as JSON or something, so you can import, deserialise and import them in the method again
Used for encoded keys:
private static PrivateKey generatePrivateKey(KeyFactory factory, byte[] content){
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
return factory.generatePrivate(privKeySpec);
}
private static PublicKey generatePublicKey(KeyFactory factory, byte[] content) {
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
return factory.generatePublic(pubKeySpec);
}
For unencoded:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp192r1");
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(new BigInteger(1, privateKeyBytes), spec);
ECNamedCurveSpec params = new ECNamedCurveSpec("secp192r1", spec.getCurve(), spec.getG(), spec.getN());
java.security.spec.ECPoint w = new java.security.spec.ECPoint(new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 0, 24)), new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 24, 48)));
PublicKey publicKey = factory.generatePublic(new java.security.spec.ECPublicKeySpec(w, params));

SoftLayer API: Order Security Certificate CSR validation

I use the following openssl command to genereate CSR:
openssl genrsa -out mytestdomain.key 2048
openssl req -new -sha256 -key mytestdomain.key -out mytestdomain.csr
I try to place a Security Certificate order from SoftLayer customer portal using the aboved mytestdomain.csr value under the "Enter Certificate Signing Rquest (CSR) , I got an error msg :
"Must match CSR Base64 encoded PEM Format
---BEGIN CERTIFICATE REQUEST--- Base64 Encoded String
--End CERTIFICATE REQUEST ---
How to use openssl to generate Base64 encoded PEM CSR ?
If I enter a correct csr value from a sample file, I can see SoftLayer does a validation request as:
https://control.softlayer.com/security/sslorders/validatecsr
and the response shows valid email address, country such as :
{"success":true,"result":{"X":"XX","xx":"XXXX, Europe","L":"XXXX City","O":"My Test","OU":"VPN","XX":"mytest.com","emailAddress":"test#mytest.com"}}
Question 2: Which method can I use to validate and extract information from CSR, similar to what the SoftLayer customer portal use?
Regarding to your questions:
Question 1: I followed the steps in this link and it works successfully for me:
https://www.instantssl.com/ssl-certificate-support/csr-generation/ssl-certificate-mod-ssl.html
This will generate .key and .csr files. You should specify the .csr file content for CSR.
Question 2: The SoftLayer_Security_Certificate_Request::validateCsr method will help to validate the CSR.
Here a PHP example:
<?php
/**
* Validate Csr
*
* This script allows you to validate a Certificate Signing Request (CSR) required
* for an SSL certificate with the certificate authority (CA). This method sends the CSR,
* the length of the subscription in months, the certificate type, and the server type for
* validation against requirements of the CA. Returns true if valid.
*
* Important manual pages:
* #see http://sldn.softlayer.com/reference/services/SoftLayer_Security_Certificate_Request/validateCsr
*
* #license <http://sldn.softlayer.com/wiki/index.php/license>
* #author SoftLayer Technologies, Inc. <sldn#softlayer.com>
*/
require_once '\vendor\autoload.php';
/**
* Your SoftLayer API username and apiKey
* #var string
* #var string
*/
$apiUsername = 'set me';
$apiKey = 'set me';
/**
* The encoded CSR data string
* #var string
*/
$csr = "-----BEGIN CERTIFICATE REQUEST-----
MIIC9TCCAd0CAQAwga8xCzAJBgNVBAYTAkJPMRMwEQYDVQQIDApDb2NoYWJhbWJh
MRMwEQYDVQQHDApDb2NoYWJhbWJhMRUwEwYDVQQKDAxSdWJlckNvbXBhbnkxFTAT
BgNVBAsMDHJ1YmVyU2VjdGlvbjEdMBsGA1UEAwwUd3d3LnJ1YmVyY3VlbGxhci5j
b20xKTAnBgkqhkiG9w0BCQEWGnJ1YmVyLmN1ZWxsYXJAamFsYXNvZnQuY29tMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw3WFBDFbqvk9O/6Wd+z0MsQQ
6WS5Vxw5iMVlo6J4xpoXqzA0FhuROv7IuJQ0rNvhDqTisMBLrUoDgvS6UgqM8RM9
DPNgGSdTVp0Z1Mt/qTavUPUfyT23msh5/Oqlo6/z+u23euKfTg4qhuVV7PG0eY6U
/GDumtmCk8+b33xzIBtLbfnB3119vRff9DmB6R7bSCzg+e8JnRycpSMKA8Egkw3N
O4k0mpvj5jR+FApFlTfKXcQU5xdEQYn1pe5+QLwSKJWP9iGEyiyFbvFVsYlKxKvh
RYEwuCqPAZBoWfO8zT4VPu2NO8QjDB55LX5xNAq2ZvHekbtWUtAzMeD6h2O04wID
AQABoAAwDQYJKoZIhvcNAQELBQADggEBAKcYJHvIvYzD+XssGHbfbyK7/arjGgyB
YyA5dx2DvwvdUGpIQyKCWyLyk10brObGoBGMtt5raxqI19UqnOpsOAJ5lF3fsM0B
mNQTAlsen/Ove/K+40Ycg1tYjLZN8vHebKvLyjENdeX4HgN+cTK030iUQq+ObwjB
te4UZsDhWlMijMay5gOcVZLI2D9uQzzMBgfymuuwync5m0ia1lmbNOmF9j9bNC5G
uN/rDbzGG4WEzbFmj/ERYgx7UGH9WkvEQA2+Dhj26SC3K9zgYkKMbaF3Kx49cBxj
xVtZtg+DLTQ8Ee5R/wB0YfGw1W3gYcVUBL/EZWv7PuqzKnBro09iuHA=
-----END CERTIFICATE REQUEST-----";
/**
* The product item identifier for the type of SSL certificate
* E.g: Item Id: 965 Description: RapidSSL - 2 year
* #var int
*/
$itemId = 965;
/**
* The type of server in which the certificate will be installed
* #var string
*/
$serverType = "apache2";
/**
* The length of the certificate subscription desired in months. Typically 12 or 24 months
* #var int
*/
$validityMonths = 24;
// Create a SoftLayer API client object for "SoftLayer_Security_Certificate_Request" service
$client = \SoftLayer\SoapClient::getClient('SoftLayer_Security_Certificate_Request', null, $apiUsername, $apiKey);
try {
$result = $client->validateCsr($csr, $validityMonths, $itemId, $serverType);
print_r($result);
} catch (\Exception $e) {
die('Unable to validated CSR: ' . $e->getMessage());
}
I hope this information can help you.
I'm not sure the types of CSR that are supported by SoftLayer, you can submit a ticket if you want more information about it.
However, if you want to validate the CSR, you can try with this: SSL Decoder, it is based on PHP. Also I extracted a little part of code from there, to get the result that you are expecting, try with this:
<?php
/**
* Function get_sans_from_csr
*/
function get_sans_from_csr($csr) {
global $random_blurp;
global $timeout;
$sans = array();
//openssl_csr_get_subject doesn't support SAN names.
$filename = "C:/Csr/tmp/csr-" . $random_blurp . "-" . gen_uuid() . ".csr.pem";
$write_csr = file_put_contents($filename, $csr);
if($write_csr !== FALSE) {
$openssl_csr_output = trim(shell_exec("timeout " . $timeout . " openssl req -noout -text -in " . $filename . " | grep -e 'DNS:' -e 'IP:'"));
}
unlink($filename);
if($openssl_csr_output) {
$csr_san_dns = explode("DNS:", $openssl_csr_output);
$csr_san_ip = explode("IP:", $openssl_csr_output);
if(count($csr_san_dns) > 1) {
foreach ($csr_san_dns as $key => $value) {
if($value) {
$san = trim(str_replace(",", "", str_replace("DNS:", "", $value)));
array_push($sans, $san);
}
}
}
if(count($csr_san_ip) > 1) {
foreach ($csr_san_ip as $key => $value) {
if($value) {
$san = trim(str_replace(",", "", str_replace("IP:", "", $value)));
array_push($sans, $san);
}
}
}
}
if(count($sans) >= 1) {
return $sans;
}
}
/**
* Function csr_parse_json
*/
function csr_parse_json($csr) {
// if csr or cert is pasted in form this function parses the csr or it send the cert to cert_parse.
global $random_blurp;
global $timeout;
$result = array();
if (strpos($csr, "BEGIN CERTIFICATE REQUEST") !== false) {
$cert_data = openssl_csr_get_public_key($csr);
$cert_details = openssl_pkey_get_details($cert_data);
$cert_key = $cert_details['key'];
$cert_subject = openssl_csr_get_subject($csr);
$result["subject"] = $cert_subject;
$result["key"] = $cert_key;
$result["details"] = $cert_details;
if ($cert_details) {
$result["csr_pem"] = $csr;
$sans = get_sans_from_csr($csr);
if(count($sans) > 1) {
$result["csr_sans"] = $sans;
}
}
} elseif (strpos($csr, "BEGIN CERTIFICATE") !== false) {
$result = cert_parse_json($csr, null, null, null, null, true);
} else {
$result = array("error" => "data not valid csr");
}
return $result;
}
/**
* Function gen_uuid
*/
function gen_uuid() {
//from stack overflow.
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
// 16 bits for "time_mid"
mt_rand( 0, 0xffff ),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand( 0, 0x0fff ) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand( 0, 0x3fff ) | 0x8000,
// 48 bits for "node"
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
);
}
// Define your csr
$data = csr_parse_json("-----BEGIN CERTIFICATE REQUEST-----
MIIC9DCCAdwCAQAwga4xCzAJBgNVBAYTAkJPMRMwEQYDVQQIDApDb2NoYWJhbWJh
MRMwEQYDVQQHDApDb2NoYWJhbWJhMRkwFwYDVQQKDBBSdWJlclRlc3RDb21wYW55
MRAwDgYDVQQLDAdzZWN0aW9uMR0wGwYDVQQDDBR3d3cucnViZXJjdWVsbGFyLmNv
bTEpMCcGCSqGSIb3DQEJARYacnViZXIuY3VlbGxhckBqYWxhc29mdC5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDw8QIBguC4qRsvb3I9K/2qO50g
zB3hEwb0DOCWa5LXUgpq3SHYohtlEdneUiRiYtn4ggO0NjZ4f4hfvQ9iZ10zH8/v
W7DeElvdJBP0dHEInuhKGP6wjieR2IkkPzsOTCeVJ6FOnxsC192qgXG0O8WjquKh
g6NZKdW0oLtl1/mWFixmWFwcjh7IUWZ/J0NpAlHBtDpYILRD84rHv1XK9GE1JUfO
euSwq6K0jRmK388Xt37bxFj5iMMpHXI55+LIpA9ZoV9NffCiGoohwp45QgEXdkfm
1NBGVXiGaQzn1HgnpdnYR05tAScOkqJ4yRkCUatE8q3F9+u8KM2e+mIxHeflAgMB
AAGgADANBgkqhkiG9w0BAQsFAAOCAQEA3TRZYZuhsQHmZ8anuMHawCcu6He5g3Yg
hpV4O06Knzblvdy9OvK1+jEPUEpTUGgyty0kU5WCru8+FL8+2/ycrUN8bisYDHlG
7KuzOuMxsz2/U/Vj3KAerv+/sIv2oDUN7otjA5smK6769gO1NjPPSXe/nDOPh3WC
YeRYRkLqCuTG6GfqmMK/o4vHrYXyxu6apvMId6PFmAEHqMZorebo8NyqvMA3pT1D
p+LuLZsqZWNsfX9iN31+PNCWvVKaDzF3z9vWmaDV61jiteRt0gOzun9GnRV2QRpS
5GjdY64A7dpB7VuVsnXePb5RbeWQQtMwwhuW01TzzlwB9yHwlel/hQ==
-----END CERTIFICATE REQUEST-----");
// Print whole result
print_r($data);
// Print "subject" property from the result
print_r($data["subject"]);
?>
All the methods used in the script were extracted from: SSL Decoder