Skip to content

Instantly share code, notes, and snippets.

@jhanley-com
Created October 1, 2021 02:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jhanley-com/28dbac060b0cebc3134f21cf6fc5a576 to your computer and use it in GitHub Desktop.
Save jhanley-com/28dbac060b0cebc3134f21cf6fc5a576 to your computer and use it in GitHub Desktop.
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