bcrypto / btok

Cryptographic tokens
4 stars 4 forks source link

Дополнительные правила парольной аутентификации #89

Open agievich opened 2 years ago

agievich commented 2 years ago

Правила парольной аутентификации заданы в подразделе 6.3 Стандарта. Вот они:

  1. КТ должен поддерживать три пароля -- PIN, CAN, PUK. Пароли используются в протоколе BPACE и являются общими для всех прикладных программ КТ. Пароли записываются на КТ при выпуске токена в обращение. Пароли PIN и PUK конфиденциально передаются владельцу, CAN передается в открытом виде.

  2. Пароль PIN (от Personal Identification Number) представляет собой случайное число из 6 десятичных цифр, известное только владельцу КТ. Используется для контроля доступа к данным и прикладным программам КТ. Может быть изменен владельцем в процессе эксплуатации КТ после ввода верного действующего PIN.

  3. PIN снабжается счетчиком попыток, который первоначально равен 3. При неверном вводе PIN счетчик уменьшается на 1. Если счетчик достигает значения 1, то PIN приостанавливается и далее требуется ввести CAN. Ввод CAN не изменяет счетчик. При верном CAN пароль PIN возобновляется -- его снова можно ввести. При неверном CAN доступ к КТ временно блокируется. Если счетчик попыток достигает значения 0, то блокируется PIN. При вводе верного PIN счетчик попыток возвращается к значению 3.

  4. PIN может быть разблокирован после ввода верного PUK. Однако если при заблокированном PIN пароль PUK вводится неверно 10 раз, то PIN блокируется навсегда. При успешной разблокировке PIN счетчик попыток возвращается к значению 3.

  5. PIN может быть деактивирован и повторно активирован с помощью специальных команд. Для деактивации требуется предъявить верный PIN или PUK, для активации -- верный PUK. Сразу после выпуска токена PIN активирован. При деактивации PIN доступ к операциям и данным, требующим аутентификации по PIN, запрещен. В том числе запрещена аутентификация по PIN, разблокировка PIN. Деактивация и повторная активация PIN не изменяют ни статус его блокировки, ни счетчик попыток.

  6. Пароль CAN (от Card Access Number) представляет собой число из 6 десятичных цифр, которое не может быть вычислено на основании общей информации о КТ (например, серийном номере) или его владельце. Может быть напечатан на корпусе КТ или указан в сопроводительных документах.

  7. Пароль CAN не может быть заблокирован или изменен. Он используется для защиты от атак типа <<отказ в обслуживании>>. Защита состоит в требовании ввести CAN перед последней проверкой PIN. Дополнительно CAN может использоваться для получения доступа к функциям и данным прикладной программы eID авторизованным терминалом, т. е. терминалом, который был успешно аутентифицирован с помощью протокола BAUTH и в сертификате которого установлено соответствующее право.

  8. Пароль PUK (от PIN Unlock Key) представляет собой случайное число из 10 десятичных цифр, известное только владельцу КТ. PUK не может быть заблокирован или изменен. Используется для разблокировки PIN. Дополнительно может использоваться для деактивации и активации PIN.

  9. После ввода неверного CAN или PUK следует временно заблокировать КТ не менее чем на 1 с. Для контроля времени блокировки следует использовать аппаратный таймер либо организовать вычисления требуемой продолжительности.

  10. При передаче в команды КТ пароли PIN, CAN и PUK представляются строками октетов, в которых октет 0x30 кодирует цифру 0 пароля, октет 0x31 -- цифру 1, ..., октет 0x39 -- цифру 9.

Правила охватывают не все аспекты парольной аутентификации. Например неясен срок действия статуса аутентификации по тому или иному паролю (PIN, CAN или PUK):

а) до конца сеанса работы с КТ; б) до первого из двух событий: окончание сеанса, успешная аутентификация по другому паролю; в) до первого из трех событий: окончание сеанса, успешная аутентификация по другому паролю, ошибка аутентификации по текущему паролю.

Считая корректным вариант в), предлагается ввести следующие дополнительные правила:

  1. Успешная аутентификация по одному из паролей PIN, CAN, PUK отменяет статус успешной аутентификации по другому паролю. Нельзя быть одновременно аутентифицированным по двум паролям.

  2. После успешной аутентификация по одному из паролей PIN, CAN, PUK можно повторно аутентифицироваться по этому же паролю. В случае успеха статус успешной аутентификации по паролю будет сохранен, в случае ошибки -- потерян.

  3. После успешной аутентификация по одному из паролей PIN, CAN, PUK можно аутентифицироваться по другому паролю. В случае успеха статус успешной аутентификации по первому паролю будет потерян, в случае ошибки -- сохранен.

  4. Даже если PIN заблокирован навсегда, аутентификация по PUK (и тем более по CAN) остается возможной.

  5. Статус успешной аутентификации по CAN должен действовать непосредственно в момент последней попытки ввода PIN. Иначе эта попытка отменяется.

olegotory commented 2 years ago

Дополнительные правила поддерживаю. Отмечу также следующее.

Пароли используются как для аутентификации, так и для формирования ключей защищенного соединения. Поэтому нужно рассмотреть случаи, когда защищенные соединения будут создаваться и разрываться для каждого из вышеописанных правил 11 -15. Наверное можно говорить, что если статус аутентификации для какого-то пароля установлен, то значит, что существует защищенное соединения, созданное на общих ключах, сформированных по протоколу BPACE на данном пароле. Более того, если защищенное соединение разрывается принудительно, то и статус соответствующего пароля сбрасывается (например, если команда имеет некорректный формат, см. п. 12.4 СТБ 34.101.79). В этом случае для правил 11 -15 будет выполняться:

Для правила 11. Если ранее была выполнена аутентификация по какому-либо паролю, то при успешной аутентификации по одному из паролей PIN, CAN, PUK старое защищенное соединение разрывается и создается новое.

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

Для правила 13. В случае успешной аутентификации на другом пароле старое защищенное соединение разрывается и создается новое, в случае ошибки -- старое не разрывается, новое не создается.

Для правил 14, 15. При успешной аутентификация по PUK или CAN для защищенного соединения справедливы правила, описанные выше для случаев 11 - 13.

Дополнительно предлагается добавить правило 16: Если защищенное соединение разрывается принудительно, то статус пароля, соответствующего защищенному соединению, сбрасывается.

agievich commented 2 years ago

Парольный автомат на языке Си, реализующий описанные правила (некоторые переходы неявно продолжаются сериализацией объектов, разрывом SM и т.д.):

typedef enum
{
    puk0,                                                    /* terminated */
    puk1, puk2, puk3, puk4, puk5, puk6, puk7, puk8, puk9,    /* puk attempts */
    pin0,                                                    /* locked */
    pin1,                                                    /* last attempt */
    pind,                                                    /* deactivated */
    pins,                                                    /* suspended */
    pin2,                                                    /* two attempts */
    pin3,                                                    /* operational */
} btok_pin_state;

typedef enum
{
    auth_none,
    auth_pin,
    auth_can,
    auth_puk,
} btok_auth_state;

typedef enum
{
    pin_ok, pin_bad, pin_deactivate, pin_activate,
    can_ok, can_bad, 
    puk_ok, puk_bad,
    auth_close, 
} btok_pwd_event;

typedef struct
{
    btok_pin_state pin : 4;
    btok_auth_state auth : 2;
} btok_pwd_state;

bool_t btokPwdTransition(btok_pwd_state* state, btok_pwd_event event)
{
    switch (event)
    {
    case auth_close:
        if (state->auth == auth_none)
            return FALSE;
        state->auth = auth_none;
        return TRUE;
    case pin_deactivate:
        if (state->auth != auth_pin && state->auth != auth_puk)
            return FALSE;
        state->pin = pind;
        if (state->auth == auth_pin)
            state->auth = auth_none;
        return TRUE;
    case pin_activate:
        if (state->pin != pind || state->auth != auth_puk)
            return FALSE;
        state->pin = pin3;
        return TRUE;
    case can_ok:
        if (state->pin == pins)
            state->pin = pin1;
        state->auth = auth_can;
        return TRUE;
    case can_bad:
        if (state->auth == auth_can)
            state->auth = auth_none;
        return TRUE;
    case puk_ok:
        if (puk1 <= state->pin && state->pin <= pin0)
            state->pin = pin3;
        state->auth = auth_puk;
        return TRUE;
    case puk_bad:
        if (puk1 <= state->pin && state->pin <= pin0)
            --state->pin;
        if (state->auth == auth_puk)
            state->auth = auth_none;
        return TRUE;
    case pin_ok:
        if (state->pin != pin1 && state->pin != pin2 && state->pin != pin3)
            return FALSE;
        state->pin = pin3;
        state->auth = auth_pin;
        return TRUE;
    case pin_bad:
        if (state->pin != pin1 && state->pin != pin2 && state->pin != pin3)
            return FALSE;
        --state->pin;
        if (state->auth == auth_pin)
            state->auth = auth_none;
        return TRUE;
    }
    return FALSE;
}