Skip to content

Проблема с определением типа KeyWrap для 12 госта (unix) #53

Description

@Fasjeit

Сейчас для совместимости с некоторыми сторонними реализациями (ФСС) необходимо осуществлять импорт ключа 12 госта с использование старого CryptoProKeyWrap. Так как определить тип KeyWrap по ключу внутри Xml невозможно, то делаем так

private SymmetricAlgorithm CryptoProUnwrap(byte[] wrapped)
{
    try
    {
        return this.CryptoProUnwrap(wrapped, GostConstants.CALG_PRO12_EXPORT);
    }
    catch (CryptographicException ex)
    {
        if (Marshal.GetHRForException(ex) == -2146893819)
        {
            // bad data - пробуем импорт на старом алгоритме
            return this.CryptoProUnwrap(wrapped, GostConstants.CALG_PRO_EXPORT);
        }
        else
        {
            throw;
        }
    }
}

Проблема возникает при использовании метода ImportKeyBlob

 internal static int ImportKeyBlob(byte[] keyBlob,
            SafeProvHandle hProv, CspProviderFlags flags,
            SafeKeyHandle hImportKey, out SafeKeyHandle hKey)
{
    int keyFlags = MapCspKeyFlags((int)flags);
    bool ret = CapiHelper.CryptImportKey(hProv, keyBlob,
        keyBlob.Length, hImportKey, keyFlags, out hKey);
    if (!ret)
        throw new CryptographicException(Marshal.GetLastWin32Error());
    int algid_class = BitConverter.ToInt32(keyBlob, 4) & (7 << 13);
    if (algid_class == (5 << 13))
        return (int)KeyNumber.Exchange;
    return (int)KeyNumber.Signature;
}

Так как для Unix Marshal.GetLastWin32Error() вернёт некорректный код ошибки. При исправлении на

internal static int ImportKeyBlob(byte[] keyBlob,
            SafeProvHandle hProv, CspProviderFlags flags,
            SafeKeyHandle hImportKey, out SafeKeyHandle hKey)
{
    int keyFlags = MapCspKeyFlags((int)flags);
    bool ret = CapiHelper.CryptImportKey(hProv, keyBlob,
        keyBlob.Length, hImportKey, keyFlags, out hKey);
    if (!ret)
    {
        var hr = Interop.CPError.GetHRForLastWin32Error();
        throw hr.ToCryptographicException();
    }
    int algid_class = BitConverter.ToInt32(keyBlob, 4) & (7 << 13);
    if (algid_class == (5 << 13))
        return (int)KeyNumber.Exchange;
    return (int)KeyNumber.Signature;
}

работает корректно.

Проблема технически может возникать и в других сценариях, ибо код CapiHelper полностью перенесён из Шарпея, и обработка ошибок полностью виндовая, на unix возможны и другие некорректные коды. С виду мы больше нигде по ним не ветвимся, поэтому править массово пока не будем (из за опасений, что получение кода ошибки в других методах теоретически может приходить к перетиранию кода, и тогда будем получать ошибку и на windows).

Хорошо добывать бы тест на это (возможно в рамках LibCore с переносом сюда).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions