Ejemplo n.º 1
0
function testMajority($results, $signedData, $myPair = null, $inGroup = null, $error = true)
{
    // Get the set of root public keys, indexed by endpoint. Note that they are raw bytes:
    $publicKeys = getRootKeys($inGroup);
    // How many are there?
    $nodesInRoot = count($publicKeys);
    if ($nodesInRoot < 3) {
        // This root isn't big enough. It's not able to obtain a majority.
        return false;
    }
    // The number of root nodes that we have successfully verified a response from.
    // The JSON to forward to other nodes. This only occurs when myPair is not null (which indicates
    // that this server is 'leading' the majority process).
    $fullSet = '';
    if ($myPair == NULL) {
        // We start with 0 - we have to verify all signatures, including our own.
        $verifiedCount = 0;
    } else {
        global $thisEntity;
        // It starts with 1 because we know at least this ones signature was successful.
        $verifiedCount = 1;
        // This route also generates JSON to forward to other nodes too.
        $fullSet = '{"' . $thisEntity['Endpoint'] . '":' . $myPair;
    }
    foreach ($results as $endPoint => $result) {
        // Get this endpoints public key (bytes):
        if (!isset($publicKeys[$endPoint])) {
            continue;
        }
        // Get the key:
        $endpointKey = $publicKeys[$endPoint];
        if (is_array($result)) {
            // JSON is already loaded.
            $resultJson =& $result;
            // Encode it to a string:
            $result = json_encode($resultJson);
        } else {
            // Load the JSON:
            $resultJson = json_decode($result, true);
        }
        // Get the signature (base64):
        $resultSig = $resultJson['signature'];
        // Verify it:
        if (verify($resultSig, $resultJson['challenge'] . $signedData, $endpointKey)) {
            // Increase the count!
            $verifiedCount++;
            if ($fullSet != '') {
                // Output the end point plus the JSON response:
                $fullSet .= ',"' . $endPoint . '":' . $result;
            }
        }
    }
    // Finish the full set:
    if ($fullSet != '') {
        $fullSet .= '}';
    }
    // The important check occurs here - do we have a majority? Must be greater than half.
    if ($verifiedCount > $nodesInRoot / 2) {
        // Majority formed!
        if ($fullSet == '') {
            return true;
        }
        return $fullSet;
    } else {
        if ($error) {
            // No majority formed.
            error('majority/notformed');
        }
    }
    // No majority formed (silent error).
    return false;
}
Ejemplo n.º 2
0
function sendToRoot($payload, $pHeader, $decodeJson = false, $location = null, $rootGroup = null)
{
    global $thisEntity, $path, $dz, $rootKeys;
    if ($location == null) {
        // Use the current path as the location (used by forwarding):
        $location = $path;
    }
    // Build the message:
    $message = '{"header":{"entity":"' . $thisEntity['Endpoint'] . '"},"protected":"' . $pHeader . '","payload":"' . $payload . '","signature":"' . base64_encode(sign($pHeader . '.' . $payload)) . '"}';
    // Forward to all other root nodes in my group.
    $group = $thisEntity['Group'];
    // The responses:
    $responses = array();
    // Are we using this group or another one?
    if ($rootGroup == null) {
        // Get the local root keys:
        if ($rootKeys == null) {
            // Root keys holds a mapping of endpoint to key.
            // We'll use it here to get those endpoints.
            getRootKeys();
        }
        // Use this group:
        $keySet = $rootKeys;
    } else {
        // Sending to some other root group.
        // Only need to send to one node here.
        // (If we send to all of them, it defeats the object of having groups!)
        // Get a random node:
        $randomRow = randomRoot($rootGroup);
        // Create the set:
        $keySet = array();
        // Add our single entry to it:
        $keySet[$randomRow['Endpoint']] = $randomRow['Key'];
    }
    global $rootErrors;
    // Clear root errors:
    $rootErrors = null;
    // For each one..
    foreach ($keySet as $endPoint => $rootKey) {
        if ($endPoint == $thisEntity['Endpoint']) {
            // Don't send to myself!
            continue;
        }
        // Send it a message:
        // Warning! This will take a while with crowded roots
        // as it does the requests one after another. Use parallel requests instead.
        $error;
        $response = post('https://' . $endPoint . '/' . $location, $message, $error);
        // Got a response?
        if ($error) {
            // The remote node emitted an error.
            if (!$rootErrors) {
                $rootErrors = array();
            }
            // Add the error:
            array_push($rootErrors, $error);
        } else {
            if ($decodeJson) {
                // Add to result:
                $responses[$endPoint] = json_decode($response, true);
            } else {
                // Add to result as-is (default):
                $responses[$endPoint] = $response;
            }
        }
    }
    // Return the responses:
    return $responses;
}