Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Fasjeit opened this issue Feb 14, 2022 · 0 comments
Assignees
Labels
bug Something isn't working Confirmed invalid This doesn't seem right Need tests

Comments

@Fasjeit
Copy link
Collaborator

Fasjeit commented Feb 14, 2022

Сейчас для совместимости с некоторыми сторонними реализациями (ФСС) необходимо осуществлять импорт ключа 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 с переносом сюда).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Confirmed invalid This doesn't seem right Need tests
Projects
None yet
Development

No branches or pull requests

1 participant