I'm trying to connect to an API and have been told that I need to send our public key to match the public key I sent them via email.
I'm setting the public key by using:
curl_setopt($c, CURLOPT_SSLCERT, [path to file]);
I'm getting this error:
unable to set private key file: [path to file] type PEM
Am I missing something? I know that typically key-based encryption requires a private and public key but they specifically wanted me to send them the public key via email and specifically want me sending them the public key via code.
Turns out that I also needed CURLOPT_SSLKEY which is the private key. Apparently cURL requires both, but sends only the public key?
Related
Hi i'm developing an architecture with an application authorization server(AS) and some client applications(CA) in PHP.
Users that are signing in a CA will login by SSO on AS and on success will be redirect to CA with some parameters stored in a JWT token.
I generate a pair of keys to implement asymmetric encryption, where private is secret and stored on the AS and public is shared around CAs.
I'm using Firebase/JWT library for PHP and i'm able to encode token generated by AS using JWT::encode($this->token, $privateKey, 'RS256') with AS private key.
At the same way the CA receives the token and decode it using
JWT::decode($jwt_token, $key, array('RS256'))
and all works fine...
But i want to introduce another secure step at the beginning.
I want generate a token in the CA(with the same library), containing referral CA infos (like app code, and other CA parameters to send to AS) before this were redirect to AS for login and i want to encrypt this token with public shared key of AS so that only AS can decrypt the token with its own private key.
In simple words Bob(CA) encrypt a message with Alice's(AS) public key so that only Alice can decrypt it with her own private key.
I'm trying to do that with same method
JWT::encode($this->token, $_ALICES_PUBLIC_KEY, 'RS256')
but it seems that the JWT::encode method only accept PRIVATE type keys and i'm getting the following error
PHP Warning: openssl_sign(): supplied key param cannot be coerced into a private key
Any help is appreciated. thanks
I created a Self-Signed cert by following this article I set the private key as exportable but there isn't an export link within the salesforce app (that I can see) so I'm guessing you have to export from the certificate itself. I'm using the PHP openssl x509 functions but i can't get it to work. I keep getting openssl_sign(): supplied key param cannot be coerced into a private key... when I run this code:
...
$private_key = openssl_get_privatekey(file_get_contents(env('SALESFORCE_CERT_FILE')));
$s = "";
openssl_sign($header . '.' . $payload, $s, $private_key, "SHA256");
...
I figured it out. In salesforce they do have an "export" button that says "Export to Keystore". I was unfamiliar with this so I didn't think to use it. I was looking for export private key or something like that. Turns out you can just following the answer to this stack exchange question to get your private key.
I'm trying to build a blockchain and for that, I need to generate a public and a private key and use the sign function and the verify function, from research I found that those functions were in the OpenSSL function, but I can't figure how this one works , I got the following code that I copied from the PHP doc :
// Create the keypair
$res=openssl_pkey_new();
// Get private key
openssl_pkey_export($res, $privkey);
// Get public key
$pubkey=openssl_pkey_get_details($res);
$pubkey=$pubkey["key"];
$data = 'plaintext data goes here';
openssl_sign("hello",$signature,$privKey);
$test=openssl_verify("hello",$signature,$pubKey,"sha256");
echo $test;
and this gives me: openssl_pkey_export(): cannot get key from parameter 1.
ps: i'm on windows
I'm trying to create the access token using box app user id. I have use the following code to create the box app user
curl https://api.box.com/2.0/users \
-H "Authorization: Bearer <TOKEN>" \
-d '{"name": "Ned Stark", "is_platform_access_only": true}' \
-X POST
Then it is give the following result
{"type":"user","id":"2199107004","name":"Ned Stark","login":"AppUser_399382_9BNZHI03nJ#boxdevedition.com","created_at":"2017-08-03T00:58:04-07:00"
Is it possible to generate the access token using box app user id.?
Edited
I have generate the Public key in BOX API. Then I have file which is having Public key and Private key detail like as bellow,
{
"boxAppSettings": {
"clientID": <Client ID>,
"clientSecret": <clientsecret>,
"appAuth": {
"publicKeyID": <publickeyid>,
"privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\Key heresn-----END ENCRYPTED PRIVATE KEY-----\n",
"passphrase": <phrase>
}
},
"enterpriseID": <enterpriseId>
}
Then I have generate header and payload, which is as follow
$header = ["typ"=> "JWT", "alg"=>"RS256","kid"=> <public key id>];
$payload = [
"iss"=> "<client id>",
"sub"=> "<APP USER ID>",
"box_sub_type"=> "user",
"aud"=>"https://api.box.com/oauth2/token",
"jti"=>"<I don't know what is this>",
"exp"=>1428699385
];
$header = base64_encode(json_encode($header));
$payload = base64_encode(json_encode($payload));
After this I got stuck how to implement the private and public key here. Actually I'm having the JSON file which is downloaded from BOX API.
And I can't understand what is the JTI? How to add the public key and|or private key JSON file in this? How to do it?
And I have generate the private key manually as per document, as follow
openssl genrsa -aes256 -out private_key.pem 2048
Then I gave the password as "12345". And generate public key as follow,
openssl rsa -pubout -in private_key.pem -out public_key.pem
Then I added the public key in BOX-API and I made a code as follow,
$data = file_get_contents('private_key.pem');
$result = openssl_pkey_get_private($data,"12345");
print_r($result);
It gives the following result
Resource id #4
These is not looking like encrypted data. And how to implement private and public when calling box api in php.?
I won't recommend you to implement this yourself since there are already a couple of libraries implementing this protocol. However I split my answer into 2 parts the first part explains how to use an open source package to solve your problem, the second part helps you out if you want to do private keys signing.
Using a package
There are a couple of php packages that support JWT signing, at the moment of writing the one that is used most is lcobucci/jwt, but there are also other implementations found here:
https://packagist.org/search/?q=jwt
You can use composer to install it. Since version 4.0 is not documented right now I suggest you install 3.2 and have a look at the README file of that version.
You can require this in your project using: composer require lcobucci/jwt:^3.2
Your code sample suggests you need RSA256, the library has an example for that:
<?php
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Keychain; // just to make our life simpler
use Lcobucci\JWT\Signer\Rsa\Sha256; // you can use Lcobucci\JWT\Signer\Ecdsa\Sha256 if you're using ECDSA keys
$signer = new Sha256();
$keychain = new Keychain();
$token = (new Builder())
->setIssuer('http://example.com') // Configures the issuer (iss claim)
->setAudience('http://example.org') // Configures the audience (aud claim)
->setId('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
->setIssuedAt(time()) // Configures the time that the token was issue (iat claim)
->setNotBefore(time() + 60) // Configures the time that the token can be used (nbf claim)
->setExpiration(time() + 3600) // Configures the expiration time of the token (nbf claim)
->set('uid', 1) // Configures a new claim, called "uid"
->sign($signer, $keychain->getPrivateKey('file://{path to your private key}')) // creates a signature using your private key
->getToken(); // Retrieves the generated token
Signing and verifying
When using public and private keys you always have to be sure to keep your private key safe. You can however easily publish your public key to the world without compromising security.
Signing is done using the private key, since you don't want people to be able to fake your signature, signing with the public part would make it possible for everyone to do it. This also means that the verify step always uses the public key, because everyone should be able to do it.
Doing it in PHP
The code example you provided simply loads a private key, but does not do any action with it. In order to sign you will need to use openssl_sign with your variable. Resource #xx simply means a reference to something external in php.
<?php
// Data to sign
$payload = 'TEST';
// Generate a new key, load with: openssl_pkey_get_private
$privateKey = openssl_pkey_new(array('private_key_bits' => 512)); // NOT SECURE BUT FAST
// Extract public part from private key
$details = openssl_pkey_get_details($privateKey);
// Use openssl_pkey_get_public to load from file
$publicKey = $details['key'];
// Generated by openssl_sign
$signature = null;
// Sign with private key
openssl_sign($payload, $signature, $privateKey, OPENSSL_ALGO_SHA256);
// Use base64 because the signature contains binairy data
echo 'Signed data: '.base64_encode($signature).PHP_EOL;
// Use publicKey to verify signature
$valid = openssl_verify($payload, $signature, $publicKey, OPENSSL_ALGO_SHA256);
echo 'Signature is '.($valid ? 'Valid' : 'Invalid').PHP_EOL;
What else
If you still want to implement the complete protocol I suggest you have another look at the package. And as already suggested by the comments the complete specification:
https://www.rfc-editor.org/rfc/rfc7519.txt
Last hint: JWT uses some different characters for base64 than php so be sure to handle that correctly.
I have followed the instructions here to obtain an access token for a web API.
https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx
I have this working but the documentation is vague when it comes to figuring out how to validate the token in PHP.
You can use the access token that is returned in the response to authenticate to a protected resources, such as a web API. Typically, the token is presented to the web API in an HTTP request using the Bearer scheme, which is described in RFC 6750. This specification explains how to use bearer tokens in HTTP requests to access protected resources.
When the web API receives and validates the token, it gives the native client application access to the web API.
How do I validate the JWT in application? I have a PHP framework which is using PHP openssl_verify() function with the token, signiture, key and algorithm but I receive error of when I use the private key from Azure with the SHA256 algorithm:
openssl_verify(): supplied key param cannot be coerced into a public key
This leads me to believe that the key I am using in PHP to validate is not correct. At the moment, I am using the private key I generated for the Active Directory Application, which happens to also be the same value I am using for the "client_secret" parameter when hitting the oauth2/token url (any other value causes no token to be generated so this is probably correct).
The key is similar to (BUT IT NOT ACTUALLY):
cLDQWERTYUI12asdqwezxctlkjpoiAn7yhjeutl8jsP=
Where I beleive openssl needs to have a certificate... if so I can't seem to find where this certificate is in the Azure portal.
What am I missing here? What is the key I should be using with openssl_verify() to verify the JWT and where do I find it in Azure?
Thanks
--
UPDATE:
I have found the public keys here: https://login.windows.net/common/discovery/keys
However I still cannot use the X5C provided to verify the signature. How do you do this in PHP?
--
UPDATE 2:
I used a converted to create a .pem file for the public key using both the 'e' and 'n' parameters. This received a public key.
Now I get OPEN SSL errors when decrypting with it:
error:0906D06C:PEM routines:PEM_read_bio:no start line
Closing this question as I have moved on from the origional issue. Updated my question with comments showing how I have progressed.
Created a new question for the new specific issue: How do I verify a JSON Web Token using a Public RSA key?
--
Just in case it helps anyone else:
For further information on a solution to obtaining a public key from Microsoft in PHP I did the following:
$string_microsoftPublicKeyURL = 'https://login.windows.net/common/discovery/keys';
$array_publicKeysWithKIDasArrayKey = loadKeysFromAzure($string_microsoftPublicKeyURL);
function loadKeysFromAzure($string_microsoftPublicKeyURL) {
$array_keys = array();
$jsonString_microsoftPublicKeys = file_get_contents($string_microsoftPublicKeyURL);
$array_microsoftPublicKeys = json_decode($jsonString_microsoftPublicKeys, true);
foreach($array_microsoftPublicKeys['keys'] as $array_publicKey) {
$string_certText = "-----BEGIN CERTIFICATE-----\r\n".chunk_split($array_publicKey['x5c'][0],64)."-----END CERTIFICATE-----\r\n";
$array_keys[$array_publicKey['kid']] = getPublicKeyFromX5C($string_certText);
}
return $array_keys;
}
function getPublicKeyFromX5C($string_certText) {
$object_cert = openssl_x509_read($string_certText);
$object_pubkey = openssl_pkey_get_public($object_cert);
$array_publicKey = openssl_pkey_get_details($object_pubkey);
return $array_publicKey['key'];
}
Its better however to cache these to disk so your not loading these them every time, but this is just a simple example of how to do this.
Then, using the array of public keys, check the JWT header for the 'kid' value to find the correct public cert to verify against and use this in parameter 3 within openssl_verify(). I used the JWT class to deal with this for me.
Using this public key array created above and the JWT class should allow you to validate microsoft JWTs.
Link to JWT class from firebase: https://github.com/firebase/php-jwt
Call JWT::Decode with param 1 of your JWT, param 2 of this public key array and param three of an array of just 'RS256'.
JWT::decode($string_JSONWebToken, $array_publicKeysWithKIDasArrayKey, array('RS256'));
This will throw an exception if the JWT is invalid or return a decrypted JWT for you to use (and check the claims).
If you want to verify the jwt then go to jwt.io
This will allow you to paste the JWT and it will then verify the header, claims, and if you add the Public key or private key (depending how the server verifies the signature) it will also verify the signature of the JWT.