id: Гость   вход   регистрация
текущее время 01:49 02/05/2024
Владелец: SATtva редакция от 19/03/2007 17:31 (автор: SATtva) Печать
создать
просмотр
редакции
ссылки

Это старая редакция страницы Разработки / Движок / Gnu P G за 19/03/2007 17:31.


Общая спецификация интеграции GnuPG [ЧЕРНОВИК]


Оглавление документа:

Задачи


Задачами, решаемыми интеграцией GnuPG, являются:


  1. Валидация загружаемого пользователем (в свой профиль) открытого ключа на корректность с последующим внесением отпечатка в базу данных.
  2. Защита приватной связи между пользователями сайта.
  3. Защита отправляемого пользователю восстановленного пароля.

Возможность аутентификации на сайте с помощью протокола запрос-ответ (подписание пользователем строки запроса, сгенерированной сервером) не определяется в числе задач, поскольку, хотя и скрывает пароль от наблюдателя на канале связи, сама по себе не в силах предотвратить несанкционированный доступ к учетной записи пользователя с помощью перехваченных cookie и иными путями. Решение же данной проблемы — SSL — вообще делает подобную схему избыточной, поскольку защищает как реквизиты авторизованной сессии (cookie/SID) при работе с сайтом, так и реквизиты пользователя (логин/пароль) в момент аутентификации.


Тем не менее, список задач остается открыт для дополнений.

Функции


Для решения означенных задач требуется реализовать следующий набор функций (достаточность и необходимость всех функций из списка подлежит обсуждению).

Загрузка/валидация ключа


Загрузка ключа выполняется на странице персональных настроек уже после регистрации и успешного входа в систему. Загрузка на этапе регистрации не имеет смысла по той причине, что HTTP-POST-запрос как целое не подвергается цифровому подписанию, и потому может быть модифицирован злоумышленником, тогда как использование SSL снимает подобные риски и на этапе регистрации, и последующего логина и изменения настроек.


Все этапы загрузки/валидации ключа выполняются в контексте специальной временной связки. Если импортированный ключ удовлетворяет необходимым условиям (см. ниже), производится его автоматический перенос в основную связку сервера.

UploadPK(keyASCII)

Импортирует загруженный ключ на временную связку. Единственный аргумент, keyASCII, представляет собой загруженный пользователем блок открытого ключа, передаваемый в GnuPG через STDIN с параметром --import. Сразу после исполнения вызывается CheckPK(keyID), которая анализирует статус-коды GPG с целью определения пригодности ключа для зашифрования.

RecievePK(keyID[, ksURL])

Импортирует ключ с сервера ключей на временную связку. Передает GnuPG указанный пользователем (в профиле) ID ключа в параметре командной строки --recv-keys. Опциональный аргумент ksURL позволяет пользователю задать URL сервера ключей, вместо дефолтного subkeys.pgp.net. Как и в предыдущем случае сразу после исполнения вызывается CheckPK(keyID).


Вопросы: следует ли перед исполнением команды с параметром --recv-keys исполнить ее с --search-keys и, если сервер вернет более одно ключа, остановить программу и выдать предупрждение (к примеру, чтобы пользователь скорректировал запрос и указал keyID в 16-значном формате)? Альтернативным способом снятия двусмысленности может быть такой: показать пользователю результаты поиска и предложить выбрать принадлежащий ему ключ. Требуется протестировать альфу и изучить статус-коды, возвращаемые в различных описанных режимах.

CheckPK(keyID)

Анализирует статус-коды, возвращенные GnuPG сразу после импорта пользовательского ключа на временную связку. Проверяет следующие условия: 1) ключ содержит по крайней мере один шифровальный подключ и 2) базовый ключ и шифровальный подключ в данный момент действительны. Оба условия не имеют критического значения при загрузке ключа (пользователю выводится только предупреждение), но при восстановлении пароля или отправке приватного сообщения операция завершится неудачей.


Определить необходимые статус-коды, подлежащие проверке, и возвращаемые функцией коды ошибки в каждом конкретном случае.

AcceptPK(keyID)

Вызывается при импорте ключа в случае положительного ответа CheckPK() и переносит импортированный ключ с временной связки на главную.

RejectPK(keyID)

Вызывается при импорте ключа в случае отрицательного ответа CheckPK() и удаляет ключ с временной связки.

DeletePK(keyID)

Удаляет открытый ключ с главной связки.

FlushTemp()

Очищает временную связку ключей.


<...>

Реализация


Ограничивающим фактором в реализации схемы выступает запрет стандартной PHP-функции exec() (что является нормой для любого виртуального хостинга). Таким образом, взаимодействие с GnuPG может осуществляться только через интерфейс CGI. Использовать с этой целью CGI-сборку PHP нерационально, поэтому итоговая конструкция представляет собой:


Файл конфигурации gpg.conf


Поскольку GnuPG должен работать в полностью автономном режиме, видится необходимым следующий конфигурационный файл:


CGI-обертка openSpace-GPG


Ничего существенного:


Класс openSpace-GPG


<?php

/*

########################################################
##          openSpace-GPG integration class           ##
########################################################

    NOTE: PHP 5.0.0 or later is required!

*/

class GPG
{
    
// VARIABLES
    
var $engine;
    var 
$keyID;
    var 
$fingerprint;
    var 
$baseurl;
    var 
$homedir;
    var 
$tempdir;
    var 
$cgiwdir;
    var 
$stsfile;

    
// CONSTRUCTOR
    
function GPG(&$engine)
    {
        
$this->engine    = & $engine;
        
$this->baseurl    = ( $this->engine->config['ssl'] == true str_replace('http://''https://'$this->engine->config['base_url']) : $this->engine->config['base_url'] );
        
$this->homedir    rtrim($this->engine->config['gpg_home'], '/');
        
$this->tempdir    rtrim($this->engine->config['gpg_temp'], '/');
        
$this->wrapper    trim($this->engine->config['gpg_wrapper'], '/');
        
$this->stfile    $this->homedir.'/status';
        
$this->srfile    $this->homedir.'/error';
    }
    
    
// call openspace-gpg wrapper
    //        $request    - additional gpg commant line parameters
    //                      (except homedir and status-file)
    //        $method        - passing method: post or get (default)
    
function Call($request$method 'get')
    {
        if (
$method != 'get' && $method != 'post'$method 'get';
        
        
$request = array(
            
'http' => array(
                
'method'    => $method,
                
'header'    => ( $method == 'post' 'Content-type: application/x-www-form-urlencoded' '' ),
                
'content'    => http_build_query(array(
                    
'hd' => $this->homedir,        // homedir
                    
'sf' => $this->stfile,        // status-file
                    
'sr' => $this->srfile,        // stderr
                    
'cl' => $request)            // command line params
                
// end of content array
            
// end of http array
        
); // end of request array
        
        
$context    stream_context_create($request);
        
$script        = @fopen($this->baseurl.$this->wrapper'r'false$context);
        
        if (!
$script)
        {
            die(
'openSpace-GPG: unable to open CGI wrapper.');
        }
        else
        {
            
// reading output till the end
            
while (false === feof($script))
            {
                
$result .= fgets($script1024);
            }
        }
        
fclose($script);
        
        
// throwing away appended error code value
        
return substr($result0strrpos($result"\n"));
    }
    
    
// check gpg operation
    
function SelfCheck()
    {
        
$gpg $this->Call('--version');

        if (
$gpg == true)
        {
            
$gpg substr($gpg0strpos($gpg"\n"));
            
            if (
stristr($gpg'gpg (gnupg)') == true) return true;
            else return 
false;
        }
        else
        {
            return 
false;
        }
    }
    
    
// Key import through webform
//    function UploadPK($
//    {
//    }
}

?>