Skip to content

Instantly share code, notes, and snippets.

@jhanley-com
Created October 1, 2021 02:39
Embed
What would you like to do?
This program prints the Microsoft JSON Web Key Set (JWKS) certificate and public keys. Also demonstrated is two methods to create a public key from the information provided by the JWKS data. For details see my article on Azure Open ID Connect JSON Web Key Set - http://www.jhanley.com/azure-openid-connect-json-web-key-set
{
"require": {
"phpseclib/phpseclib": "^2.0",
}
}
<?php
/*****************************************************************************
* Date Created: 2021-09-30
* Last Update: 2021-09-30
* https://www.jhanley.com - Google Cloud
* Copyright (c) 2021, John J. Hanley
* Author: John J. Hanley
* License: MIT
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
/*
* This program prints the Microsoft JSON Web Key Set (JWKS) certificate and
* public keys. Also demonstrated is two methods to create a public key from
* the information provided by the JWKS data.
*/
declare(strict_types = 1);
require 'vendor/autoload.php';
use phpseclib\Crypt\RSA;
$openid_configuration_uri = 'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration';
$microsoft_jwks_uri = '';
function custom_file_get_contents($path, &$error_msg)
{
/*
* This is a custom wrapper for file_get_contents.
* The purpose is to catch errors in a string and return
* the error message to the calling function.
*/
$error_msg = "";
$contents = @file_get_contents($path);
if (empty($contents))
{
$msg = error_get_last()['message'];
$error = explode(': ', $msg);
$error_msg = trim($error[count($error) - 1]);
return "";
}
return strval($contents);
}
function load_openid_configuration()
{
/*
* Load the Microsoft OpenID Connect Metadata Document.
*/
global $openid_configuration_uri;
global $microsoft_jwks_uri;
echo 'loading: ' . $openid_configuration_uri . PHP_EOL;
$content = custom_file_get_contents($openid_configuration_uri, $error_msg);
if (empty($content))
{
echo "Error: Cannot read configuration from $openid_configuration_uri" . PHP_EOL;
echo "Message: $error_msg" . PHP_EOL;
return 1;
}
$config = json_decode($content, true);
$microsoft_jwks_uri = $config['jwks_uri'];
# echo $microsoft_jwks_uri . PHP_EOL;
return 0;
}
function get_public_key($key)
{
/*
* Create a public key from Modulus and Exponent.
*/
# echo PHP_EOL;
# echo 'N: ' . $key['n'] . PHP_EOL;
# echo 'E: ' . $key['e'] . PHP_EOL;
$n = $key['n']; # Modulus
$e = $key['e']; # Exponent
$n = strtr($n, '-_', '+/');
$rsa = new RSA();
$key = "<RSAKeyPair>"
. "<Modulus>" . $n . "</Modulus>"
. "<Exponent>" . $e . "</Exponent>"
. "</RSAKeyPair>";
$rsa->loadKey($key, RSA::PUBLIC_FORMAT_XML);
# echo $rsa . PHP_EOL;
# CRYPT_RSA_PUBLIC_FORMAT_PKCS1
return $rsa;
}
function make_certificate($key)
{
/*
* Create a certificate from the x5c value
*/
$cert = "-----BEGIN CERTIFICATE-----\n";
$cert .= $key['x5c'][0] . "\n";
$cert .= "-----END CERTIFICATE-----";
return $cert;
}
function get_public_key_from_cert($cert)
{
/*
* Extract the public key from a certificate.
*/
$pub_key = openssl_pkey_get_public($cert);
$keyData = openssl_pkey_get_details($pub_key);
return $keyData['key'];
}
function print_public_certificates()
{
/*
* Load the Microsoft JSON Web Key Set and print the certificate and
* public key for each Key ID. This function prints the public key twice.
* This function demonstrates how to create a public key from the Modulus
* and Exponent, and from a certificate.
*/
global $microsoft_jwks_uri;
echo 'loading public certificates from ' . $microsoft_jwks_uri . PHP_EOL;
$content = custom_file_get_contents($microsoft_jwks_uri, $error_msg);
if (empty($content))
{
echo "Error: Cannot read configuration from $microsoft_jwks_uri" . PHP_EOL;
echo "Message: $error_msg" . PHP_EOL;
return;
}
$config = json_decode($content, true);
foreach($config as $keys)
{
foreach($keys as $key)
{
echo PHP_EOL;
echo "Key ID: " . $key['kid'] . PHP_EOL;
$cert = make_certificate($key);
echo "Certificate" . PHP_EOL;
echo $cert . PHP_EOL;
echo "Public Key from cert:" . PHP_EOL;
echo get_public_key_from_cert($cert) . PHP_EOL;
echo "Public Key from m,e:" . PHP_EOL;
echo get_public_key($key) . PHP_EOL;
}
}
}
# Load the OpenID Connect Metadata Document
$ret = load_openid_configuration();
if ($ret !== 0)
{
exit(1);
}
print_public_certificates();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment