function rp_decrypt_verify_id_token($id_token) { $response = array(); $jwt_parts = jwt_to_array($id_token); if (isset($jwt_parts[0]['enc'])) { // encrypted echo "Encrypted ID Token - {$jwt_parts[0]['enc']} {$jwt_parts[0]['alg']} {$jwt_parts[0]['int']}\n"; $response['jwe'] = $jwt_parts; $signed_jwt = jwt_decrypt($id_token, RP_PKEY, true); if (!$signed_jwt) { echo "Unable to decrypt ID Token response"; return false; } } else { // signed $signed_jwt = $id_token; // echo "Signed ID Token {$jwt_parts[0]['alg']}\n"; } if ($signed_jwt) { list($header, $payload, $sig) = jwt_to_array($signed_jwt); // echo "Signed ID Token {$header['alg']}\n"; $response['jws'] = array($header, $payload, $sig); if ($header['alg'] == 'none') { $verified = true; } else { $verified = jwt_verify($signed_jwt); } // echo "Signature Verification = $verified"; if ($verified) { if (isset($payload['address']) && is_array($payload['address'])) { if (isset($payload['address']['formatted'])) { $payload['address'] = $payload['address']['formatted']; } else { $payload['address'] = "{$payload['address']['street_address']}\n{$payload['address']['locality']}, {$payload['address']['region']} {$payload['address']['postal_code']}\n{$payload['address']['country']}"; } } if (isset($payload['aud']) && is_array($payload['aud'])) { $payload['aud'] = implode(', ', $payload['aud']); } $g_id_response = $payload; // echo "ID Token Signature Verified\n"; $_SESSION['login'] = $payload['sub']; } else { echo "ID Token Signature Verification Failed\n"; } } return $response; }
function is_client_authenticated() { try { $auth_type = ''; if (isset($_REQUEST['client_assertion_type'])) { $auth_type = $_REQUEST['client_assertion_type']; log_debug("client_assertion_type auth %s", $auth_type); if ($auth_type != 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer') { throw new OidcException('unauthorized_client', 'Unknown client_assertion_type'); } $jwt_assertion = $_REQUEST['client_assertion']; if (!isset($jwt_assertion)) { throw new OidcException('unauthorized_client', 'client_assertion not available'); } list($jwt_header, $jwt_payload, $jwt_sig) = jwt_to_array($jwt_assertion); if ($jwt_payload['iss'] != $jwt_payload['sub']) { throw new OidcException('invalid request', 'JWT iss and prn mismatch'); } $client_id = $jwt_payload['iss']; log_debug("header = %s\npayload = %s\n", print_r($jwt_header, true), print_r($jwt_payload, true)); log_debug("assertion = %s", $jwt_assertion); $alg_prefix = substr($jwt_header['alg'], 0, 2); if ($alg_prefix == "HS") { $auth_type = 'client_secret_jwt'; } elseif ($alg_prefix == "RS") { $auth_type = 'private_key_jwt'; } log_debug("auth_type = %s", $auth_type); } elseif (isset($_SERVER['PHP_AUTH_USER'])) { $client_id = $_SERVER['PHP_AUTH_USER']; if (isset($_SERVER['PHP_AUTH_PW'])) { $client_secret = $_SERVER['PHP_AUTH_PW']; } $auth_type = 'client_secret_basic'; } elseif (isset($_REQUEST['client_id'])) { $client_id = $_REQUEST['client_id']; if (isset($_REQUEST['client_secret'])) { $client_secret = $_REQUEST['client_secret']; } $auth_type = 'client_secret_post'; } else { throw new OidcException('invalid_request', 'Unknown authentication type'); } if (!$client_id || !($client_secret || $jwt_assertion)) { throw new OidcException('invalid_client', 'no client or secret'); } // perform client_id and client_secret check $db_client = db_get_client($client_id); if ($db_client) { log_debug("%s\n%s", $db_client['client_id'], $db_client['token_endpoint_auth_method']); $db_client = $db_client->toArray(); $token_endpoint_auth_method = $db_client['token_endpoint_auth_method']; if (!$token_endpoint_auth_method) { $token_endpoint_auth_method = 'client_secret_basic'; } } else { throw new OidcException('unauthorized_client', 'client_id not found'); } if ($token_endpoint_auth_method != $auth_type) { throw new OidcException('unauthorized_client', "mismatched token endpoint auth type {$auth_type} != {$db_client['token_endpoint_auth_method']}"); } switch ($token_endpoint_auth_method) { case 'client_secret_basic': case 'client_secret_post': $client_authenticated = db_check_client_credential($client_id, $client_secret); log_info("authenticating client_id %s with client_secret %s\nResult : %d", $client_id, $client_secret, $client_authenticated); break; case 'client_secret_jwt': $sig_verified = jwt_verify($jwt_assertion, $db_client['client_secret']); if ($db_client['token_endpoint_auth_signing_alg']) { $alg_verified = $db_client['token_endpoint_auth_signing_alg'] == $jwt_header['alg']; } else { $alg_verified = true; } if (substr($_SERVER['PATH_INFO'], 0, 2) == '/1') { $audience = OP_ENDPOINT . '/1/token'; } else { $audience = OP_ENDPOINT . '/token'; } $aud_verified = (is_array($jwt_payload['aud']) ? $jwt_payload['aud'][0] : $jwt_payload['aud']) == $audience; $now = time(); $time_verified = abs($now - $jwt_payload['iat'] <= 180) && abs($now - $jwt_payload['exp'] < 180); if (!$sig_verified) { log_info("Sig not verified"); } if (!$aud_verified) { log_info("Aud not verified %s != %s", $jwt_payload['aud'], $audience); } if (!$time_verified) { log_info('Time not verified'); } if (!$alg_verified) { log_info("Signing Alg does not match %s != %s", $jwt_header['alg'], $db_client['token_endpoint_auth_signing_alg']); } $client_authenticated = $sig_verified && $aud_verified && $time_verified && $alg_verified; log_info(" client_secret_jwt Result : %d %d %d %d %d", $client_authenticated, $sig_verified, $aud_verified, $time_verified, $alg_verified); break; case 'private_key_jwt': $pubkeys = array(); if ($db_client['jwks_uri']) { $pubkeys['jku'] = $db_client['jwks_uri']; } if ($db_client['jwks']) { $pubkeys['jwk'] = $db_client['jwks']; } $sig_verified = jwt_verify($jwt_assertion, $pubkeys); if ($db_client['token_endpoint_auth_signing_alg']) { $alg_verified = $db_client['token_endpoint_auth_signing_alg'] == $jwt_header['alg']; } else { $alg_verified = true; } if (substr($_SERVER['PATH_INFO'], 0, 2) == '/1') { $audience = OP_ENDPOINT . '/1/token'; } else { $audience = OP_ENDPOINT . '/token'; } $aud_verified = (is_array($jwt_payload['aud']) ? $jwt_payload['aud'][0] : $jwt_payload['aud']) == $audience; $now = time(); $time_verified = abs($now - $jwt_payload['iat'] <= 180) && abs($now - $jwt_payload['exp'] < 180); if (!$sig_verified) { log_info("Sig not verified"); } if (!$aud_verified) { log_info('Aud not verified'); } if (!$time_verified) { log_info('Time not verified'); } if (!$alg_verified) { log_info("Signing Alg does not match %s != %s", $jwt_header['alg'], $db_client['token_endpoint_auth_signing_alg']); } $client_authenticated = $sig_verified && $aud_verified && $time_verified && $alg_verified; log_info("private_key_jwt Result : %d %d %d %d %d", $client_authenticated, $sig_verified, $aud_verified, $time_verified, $alg_verified); break; default: throw new OidcException('invalid_request', 'Unknown authentication type'); } return $client_authenticated; } catch (OidcException $e) { send_error(NULL, $e->error_code, $e->desc); } catch (Exception $e) { send_error(NULL, '', $e->getMessage() . ' ' . $e->getTraceAsString()); } return false; }
function rp_decrypt_verify_id_token($id_token) { global $g_id_response, $g_info, $g_error; $response = array(); $jwt_parts = jwt_to_array($id_token); if (isset($jwt_parts[0]['enc'])) { // encrypted $g_info .= "Encrypted ID Token - {$jwt_parts[0]['enc']} {$jwt_parts[0]['alg']} {$jwt_parts[0]['int']}\n"; $response['jwe'] = $jwt_parts; $signed_jwt = jwt_decrypt($id_token, RP_ENC_PKEY, true, RP_ENC_PKEY_PASSPHRASE); if (!$signed_jwt) { $g_error .= "Unable to decrypt ID Token response"; log_error('%s', $g_error); return; } } else { // signed $signed_jwt = $id_token; $g_info .= "Signed ID Token {$jwt_parts[0]['alg']}\n"; } if ($signed_jwt) { list($header, $payload, $sig) = jwt_to_array($signed_jwt); $g_info .= "Signed ID Token {$header['alg']}\n"; $response['jws'] = array($header, $payload, $sig); if (substr($header['alg'], 0, 2) == 'HS') { $verified = jwt_verify($signed_jwt, $_SESSION['provider']['client_secret']); } elseif (substr($header['alg'], 0, 2) == 'RS') { $pubkeys = array(); if ($_SESSION['provider']['jwks_uri']) { $pubkeys['jku'] = $_SESSION['provider']['jwks_uri']; } $verified = jwt_verify($signed_jwt, $pubkeys); } elseif ($header['alg'] == 'none') { $verified = true; } log_info("Signature Verification = %d", $verified); if ($verified) { if (isset($payload['address']) && is_array($payload['address'])) { if (isset($payload['address']['formatted'])) { $payload['address'] = $payload['address']['formatted']; } else { $payload['address'] = "{$payload['address']['street_address']}\n{$payload['address']['locality']}, {$payload['address']['region']} {$payload['address']['postal_code']}\n{$payload['address']['country']}"; } } if (isset($payload['aud']) && is_array($payload['aud'])) { $payload['aud'] = implode(', ', $payload['aud']); } $g_id_response = $payload; $g_info .= "ID Token Signature Verified\n"; $_SESSION['id_token'] = $signed_jwt; } else { $g_info .= "ID Token Signature Verification Failed\n"; } } return $response; }