CryptoPro / libcore

44 stars 0 forks source link

Возможность проверки статуса лицензии КриптоПро #13

Closed k0st1x closed 1 year ago

k0st1x commented 1 year ago

Есть ли возможность, используя net6 api, проверить лицензию криптопро? Или только с помощью вызова command line такое можно проверить?

Fasjeit commented 1 year ago

Встроенных механизмов проверки лицензий CSP в libcore нет.

Программно, насколько я знаю, можно через COM объект (поиск по форуму CPCSPLicense), но для linux + дотнет это не подойдёт.

Если задача проверить только действительность лицензии на данный момент можно воспользоваться P/Invoke CPGetProvParam с флагом PP_LICENSE. Данный вызов возвращает true/false результата проверки текущей лицензии. Подробнее - по ссылке.

Если нужны сроки действия то, кажется, вариант позвать cmd/bash/pwsh и распарсить ответ будет самым простым, если это единичное действие.

k0st1x commented 1 year ago

@Fasjeit, изначально не смог понять, как реализовать описанный вами функционал. Можете ли направить, как должен выглядеть DllImport для данного метода? В какиз сборках (для windows и для Linux) обитает данная функция?

Fasjeit commented 1 year ago
public static class TestImport
{
    // linux:
    //internal const string Advapi32 = "libcapi10";

    // windows:
    internal const string Advapi32 = "advapi32.dll";

    internal enum CryptProvParam : int
    {
        PP_LICENSE = 158,
    }

    internal enum CryptGetKeyParamFlags : int
    {
        CRYPT_EXPORT = 0x0004,
    }

    [Flags]
    internal enum CryptAcquireContextFlags : uint
    {
        CRYPT_VERIFYCONTEXT = 0xF0000000      // CRYPT_VERIFYCONTEXT
    }

    [DllImport(TestImport.Advapi32, SetLastError = true, CharSet = CharSet.Ansi, EntryPoint = "CryptAcquireContextA")]
    public static extern bool CryptAcquireContext(
        out IntPtr hProv,
        string? szContainer,
        string? szProvider,
        int dwProvType,
        uint dwFlags);

    [DllImport(TestImport.Advapi32, SetLastError = true)]
    public static extern bool CryptGetProvParam(
        IntPtr safeProvHandle,
        int dwParam,
        [MarshalAs(UnmanagedType.LPStr)] StringBuilder? pbData,
        ref int dwDataLen,
        int dwFlags);

    public static bool GetLicenseStatus()
    {
        if (!TestImport.CryptAcquireContext(
            out var hProv,
            null,
            null,
            80,
            (uint)TestImport.CryptAcquireContextFlags.CRYPT_VERIFYCONTEXT))
        {
            throw new Exception();
        }

        var licenseStringBuilder = new StringBuilder();

        int len = 0;
        var result = TestImport.CryptGetProvParam(
            hProv,
            (int)TestImport.CryptProvParam.PP_LICENSE,
            null,
            ref len,
            (int)TestImport.CryptGetKeyParamFlags.CRYPT_EXPORT);

        TestImport.CryptGetProvParam(
            hProv,
            (int)TestImport.CryptProvParam.PP_LICENSE,
            licenseStringBuilder,
            ref len,
            (int)TestImport.CryptGetKeyParamFlags.CRYPT_EXPORT);

        var licenseValue = licenseStringBuilder.ToString();

        return result;
    }
}

ps. Не забыть в конце также обязательно позвать CryptReleaseContext для hProv, желательно в finaly или обернув указатели в SafeHandle + using.

k0st1x commented 1 year ago

@Fasjeit спасибо большое за указанный код. есть пара технических вопросов.

1) Запускаю полученный код на Windows машине с лицензией - возвращает true. Запускаю код на Windows машине с истёкшей лицензией - тоже получаю true. Непонятно, есть ли разница, если лицензия истекла? или из API эту разницу не узнать?

2) Вижу что в CryptReleaseContext надо указывать dwFlag, но не знаю, какую именно константу туда надо передать, тк в документации нет описания, что именно туда передать. Можете ли направить?

Fasjeit commented 1 year ago
  1. Попробуйте посмотреть на результат второго вызова функции CryptGetProvParam. Возможно не совсем корректно сделал пример и стоит смотреть на него. Если не поможет - сообщите, дополнительно посмотрю существующий код для нахождения корректного использования.
  2. Флаги не используются (т.е. передавать нужно просто 0), по аналогии с родной функцией для виндового провайдера - https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptreleasecontext
k0st1x commented 1 year ago

@Fasjeit спасибо, что направляете, но пока не получается найти правильный путь. Метод CryptGetProvParam(hrpv, PP_LICENSE,...) возвращает true даже в trial-режиме, даже если смотреть на результат второго вызова метода.

Fasjeit commented 1 year ago

Попробуйте вместо (int)TestImport.CryptGetKeyParamFlags.CRYPT_EXPORT указать 0, т.е. вызов функции такой, в result2 должен быть false на "плохой" лицензии:

var result = TestImport.CryptGetProvParam(
    hProv,
    (int)TestImport.CryptProvParam.PP_LICENSE,
    null,
    ref len,
    0);

var result2 = TestImport.CryptGetProvParam(
    hProv,
    (int)TestImport.CryptProvParam.PP_LICENSE,
    licenseStringBuilder,
    ref len,
    0);
k0st1x commented 1 year ago

@Fasjeit, теперь работает. Спасибо большое за продуктивную помощь с Вашей стороны!