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

Сломался Gost EnvelopedCMS на win, не работал на Linux #56

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

Comments

@Fasjeit
Copy link
Collaborator

Fasjeit commented May 16, 2022

Поломался EnvelopedCms, скорее всего после очередного вливания из upstream. Тестов не было....

При вызове
envelopedCms.Encrypt(recip1);

вываливается
ASN1 bad tag value met

Проблема в том, что после одного из вливаний появился код в PkcsPalWindows.Encrypt.cs

 using (SafeCertContextHandle hCertContext = recipient.Certificate.CreateCertContextHandle())
 {
    CERT_CONTEXT* pCertContext = hCertContext.DangerousGetCertContext();
    CERT_INFO* pCertInfo = pCertContext->pCertInfo;

    CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO* pEncodeInfo = (CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO*)(hb.Alloc(sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO)));

    pEncodeInfo->cbSize = sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO);

    RSAEncryptionPadding padding = recipient.RSAEncryptionPadding;

    if (padding is null)
    {
        if (recipient.Certificate.GetKeyAlgorithm() == Oids.RsaOaep)
        {
            byte[] parameters = recipient.Certificate.GetKeyAlgorithmParameters();

            if (parameters == null || parameters.Length == 0)
            {
                padding = RSAEncryptionPadding.OaepSHA1;
            }
            else if (!PkcsHelpers.TryGetRsaOaepEncryptionPadding(parameters, out padding, out _))
            {
                throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException();
            }
        }
        else
        {
            padding = RSAEncryptionPadding.Pkcs1;
        }
    }

    if (padding == RSAEncryptionPadding.Pkcs1)
    {
        // ГОСТ ПОПАДАЕТ СЮДА!
        // в результате в параметры и OID попадает RSA, а не гост
        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.Rsa);
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaPkcsParameters.Length;
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaPkcsParameters);
    }
    else if (padding == RSAEncryptionPadding.OaepSHA1)
    {
        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep);
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha1Parameters.Length;
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha1Parameters);
    }
    else if (padding == RSAEncryptionPadding.OaepSHA256)
    {
        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep);
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha256Parameters.Length;
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha256Parameters);
    }
    else if (padding == RSAEncryptionPadding.OaepSHA384)
    {
        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep);
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha384Parameters.Length;
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha384Parameters);
    }
    else if (padding == RSAEncryptionPadding.OaepSHA512)
    {
        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep);
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha512Parameters.Length;
        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha512Parameters);
    }
    else
    {
        throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException();
    }

    pEncodeInfo->pvKeyEncryptionAuxInfo = IntPtr.Zero;
    pEncodeInfo->hCryptProv = IntPtr.Zero;

    pEncodeInfo->RecipientPublicKey = pCertInfo->SubjectPublicKeyInfo.PublicKey;

    pEncodeInfo->RecipientId = EncodeRecipientId(recipient, hCertContext, pCertContext, pCertInfo, hb);

    return pEncodeInfo;
}

когда раньше было явное копирование

// KeyEncryptionAlgorithm.pszObjId
IntPtr pszObjId = new IntPtr((long) pKeyEncryptionAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId"));
Marshal.WriteIntPtr(pszObjId, encryptParam.rgszObjId[index].DangerousGetHandle());

// KeyEncryptionAlgorithm.Parameters
IntPtr pParameters = new IntPtr((long) pKeyEncryptionAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters"));

// KeyEncryptionAlgorithm.Parameters.cbData
IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.cbData);

// KeyEncryptionAlgorithm.Parameters.pbData
IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.pbData);
@Fasjeit Fasjeit added bug Something isn't working invalid This doesn't seem right Confirmed Need tests labels May 16, 2022
@Fasjeit Fasjeit self-assigned this May 16, 2022
@Fasjeit
Copy link
Collaborator Author

Fasjeit commented May 16, 2022

Чиним явным копированием для ГОСТа

if (padding == RSAEncryptionPadding.Pkcs1)
  {
  // begin: gost
  switch (recipient.Certificate.GetKeyAlgorithm())
  {                            
      case Oids.Gost3410:
      case Oids.Gost3410_2012_256:
      case Oids.Gost3410_2012_512:
      {
          // copy from cert info explicitly
          pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(recipient.Certificate.GetKeyAlgorithm());
  
          // uint, копируем
          pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData;
  
          // копируем из памяти и записываем
          var pbDataBytes = new byte[pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData];
          Marshal.Copy(pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData, pbDataBytes, 0, pbDataBytes.Length);
          pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(pbDataBytes);
          break;
          
      }
      default:
      {
          // end: gost
          pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.Rsa);
          pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaPkcsParameters.Length;
          pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaPkcsParameters);
          break;
      }
  }

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented May 16, 2022

и добавляем тест из шарпея.

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented May 16, 2022

... почему то не заработал csp-non persist сертификат при проверке Cms, не смог выкусить keyspec. В целом минор, но нужно будет выяснить в чём дело и можно ли исправить.

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented May 16, 2022

На unix видимо и не работал.
CryptMsgGetParam(CMSG_ENVELOPE_ALGORITHM_PARAM) возвращает -2146889724 - Invalid cryptographic message type.

Судя по jira (https://jira.cp.ru/browse/CPCSP-11233) поведение методов исправлено только 15 октября 20 года, используемая версия csp для тестов - не позднее 27 августа.

Раньше точно не работало - https://www.cryptopro.ru/forum2/default.aspx?g=posts&m=61697#post61697

Актуализировать версию csp, проверить ещё раз.

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented May 16, 2022

Обновился до CSP 5.0.12417-6, помогло с CMSG_ENVELOPE_ALGORITHM_PARAM, теперь падаем с CMSG_CERT_COUNT_PARAM.

@Fasjeit Fasjeit changed the title Сломался Gost CMS Сломался Gost EnvelopedCMS на win, не работал на Linux May 16, 2022
@Fasjeit
Copy link
Collaborator Author

Fasjeit commented May 16, 2022

Поддержка CMSG_CERT_COUNT_PARAM в capilight
https://jira.cp.ru/browse/CPCSP-12931

@dipsx
Copy link

dipsx commented May 26, 2022

Нет еще прогнозов когда примерно сможете поправить?)

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented May 26, 2022

Windows должен работать, на Linux ждём доработку в csp.

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented May 31, 2022

Починили CMSG_CERT_COUNT_PARAM. Можем шифровать в ночной csp. Csp в сборке пока не обновлял.

Теперь чиним CMSG_UNPROTECTED_ATTR_PARAM, ибо не можем расшифровывать.
https://jira.cp.ru/browse/CPCSP-12965

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented Jun 6, 2022

Починили CMSG_UNPROTECTED_ATTR_PARAM. Версия с исправлениями - 5.0.12515

Сломались в corefx при поиске сертификата получателя по cn (строка из cms обрезалась до первого символа, и как результат не находил получателя) - тоже починили.

Расшифрование чувствительно к сроку действия закрытого ключа (пишет access denied). Если будут падать тесты на этом - отключить временно тест.

Fasjeit added a commit that referenced this issue Jun 6, 2022
@Fasjeit
Copy link
Collaborator Author

Fasjeit commented Jun 6, 2022

Тест ожидаемо ломается в ожидаемом месте. С отключение срока действия ключа пока вопрос.

Убираю пока тест с unix. На винде остаётся.

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented Jun 7, 2022

Проблема теста с контейнером на два ключа - на никсах ведёт себя иначе. Судя по всему шифрует и пытается расшифровать на ключе подписи.

Надо будет перегенерить нормально ключевые контейнеры.

@Fasjeit
Copy link
Collaborator Author

Fasjeit commented Jun 7, 2022

В текущем релизе csp правок ещё нет, ждём следующего. После чего релизим corefx.

Также надо будет обновить инструкцию по сборке в DotnetSampleProject, указав новые версии csp.

В мастере всё должно работать с ночным csp (5.0.12515) на unix.
Windows работает и на более старых версиях.

Ночную сборку мастера corefx можно взять тут
win - https://ci.appveyor.com/project/CryptoPro/corefx/build/job/poqe4onpj1brqyvp/artifacts
unix - https://ci.appveyor.com/project/CryptoPro/corefx/build/job/akb1y6ks72sqaucg/artifacts

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

2 participants