Пришла пора исполнить свой гражданский долг – заплатить налоги. Платить налоги мы будем через портал Госуслуги. В личный кабинет портала Госуслуг будем входить с помощью электронной подписи (терминология портала Госуслуг ), т.е. имея на руках сертификат, полученный в аккредитованном удостоверяющем центре (УЦ), и закрытый ключ. И то и другое я храню на токене PKCS#11 с поддержкой российской криптографии:



И вот, выполнив свой гражданский долг, я решил еще раз проверить работу электронной подписи в офисном пакете libreoffice.

Почему я решил это сделать? Для доступа к порталу Госуслуг я использую ОС Linux и браузер Redfox, который представляет собой доработанный с учетом поддержки российской криптографии браузер Mozilla Firefox. Как известно, офисный пакет libreoffice в качестве хранилища сертификатов также использует хранилище NSS.

Браузер Redfox-52 был установлен в папку /usr/lical/lib64/firefox-52.

Для подключения библиотек пакета NSS (Network Security Services) с поддержкой ГОСТ-алгоритмов устанавливаем значение переменной LD_LIBRARY_PATH следующим образом:

$export LD_LIBRARY_PATH=/usr/lical/lib64/firefox-52:$LD_LIBRARY_PATH
$

В качестве хранилища сертификатов в libreoffice как правило используется хранилище сертификатов из браузера Firefox, почтового клиента Thunderbird или интегрированного пакета Seamonkey. Ничто не мешает использовать хранилище сертификатов браузеров GoogleChrome/Cromium или создать свое независмое хранилище (Сервис->Параметры->Безопасность->Сертификат):



После того как выбрано хранилище, подключены библиотеки, запускаем libreoffice, создаем файл формата odt и пытаемся его подписать (Файл->Цифровые подписи->Цифровые подписи).

Сертификаты в хранилище Firefox/NSS успешно отображаются и проверяются:



Однако, подпись после выбора сертификата и нажатия кнопки «ОК» не формируется:



Похоже libreoffice не хочет понимать российские криптоалгоритмы, несмотря на то, что используется NSS из браузера Redfox, который понимает ГОСТ-овые алгоритмы, что подтверждается успешной проверкой сертификатов.

Делаем вторую попытку: на этот раз попытаемся подписать PDF-файл. Для этого подготовленный документ экспортируем в PDF-формат. Для подписания PDF-файла его, естественно, необходимо загрузить (Файл->Цифровые подписи->Подписать PDF). После его загрузки пытаемся его подписать (Файл->Цифровые подписи->Цифровые подписи) (см.выше, выбираем сертификат, прописываем, например, цель подписания документа):



И подпись формируется!!! Мы видим, что подпись, сформирования на базе сертификата «Test 12 512» с ключом ГОСТ Р 34.10-2012 512 бит. Подпись верна.

Выходим из libreoffice. Снова запускаем libreoffice, загружаем подписанный pdf-файл, проверяем подписи. Все ОК. Просматривает сертификаты подписантов. Все ОК. Чудеса! Подпись PDF-файлов работает. Ставим вторую, третью подпись… Все работает. Но что-то не дает покоя. Делаем дополнительную проверку.

Открываем подписанный PDF-файл (я использовал встроенный редактор от mc – Midnight Commander — консольный файловый менеджер для Linux). Находим электронную подпись (/Type/Sig/ ):



Как видим, подпись хранится в символьном шестнадцатеричном виде. Копируем ее и сохраняем в файле. Для конвертации файла в бинарный вид (DER-кодировка) воспользуемся утилитой xxd:

$xxd –p –r <файл с подписью из PDF>  > <файл>.der 
$

Полученный файл содержит отсоединенную подпись формата PKCS#7 в DER-кодировке. Теперь это подпись можно просмотреть любым asn1-prase-ом, например, утилитой openssl. Но поскольку мы говорим о пакете NSS, то воспользуемся утилитой derdump или утилитой pp:

$pp –t p7 –u –i pkcs7_detach.p7
PKCS #7 Content Info:
    PKCS #7 Signed Data:
        Version: 1 (0x1)
        Digest Algorithm List:
            Digest Algorithm (1): SHA-256
        Content Information:
            PKCS #7 Data:
                <no content>
        Certificate List:
            Certificate (1):
                Data:
                    Version: 3 (0x2)
                    Serial Number: 4107 (0x100b)
                    Signature Algorithm: GOST R 34.10-2012 signature with GOST R 34.11-2012-512
                    Issuer: "E=ca_12_512@lissi.ru,OGRN=1234567890123,INN=1234
                        56789012,CN=УЦ 12_512,O=УЦ 12_512,L=GnuPG ГОСТ
                        -2012-512,ST=Московская область,C=RU"
                    Validity:
                        Not Before: Sat Sep 08 07:17:56 2018
                        Not After : Tue Sep 12 07:17:56 2023
                    Subject: "C=RU,ST=Московская область,CN=Ф
                         И О,SN=Фам,givenName=И О,E=xx@xx.ru,L=Город
                        ,STREET=Улица,INN=123456789012,SNILS=12345678901"
                    Subject Public Key Info:
                        Public Key Algorithm: GOST R 34.10-2012 512 Public Key:
.  .  .
                Digest Encryption Algorithm: GOST R 34.10-2012 Key 512
                Encrypted Digest:
                    34:9d:6f:37:e6:60:00:ed:fe:ef:f7:96:db:52:66:e1:
                    47:4c:5d:da:7f:9f:f3:20:50:ac:73:6c:97:db:f9:8d:
                    43:9b:8f:40:61:99:d3:4b:17:08:b8:34:e3:1e:92:76:
                    b1:0c:dd:37:01:1e:2a:30:45:68:06:af:3d:33:5e:2f:
                    71:c8:17:b3:a9:8a:6b:2f:78:9e:e4:b2:00:59:6f:5a:
                    a0:c5:9e:be:1e:4b:ca:d5:64:25:50:1a:6f:f9:55:b8:
                    3a:cf:37:a0:04:eb:89:b4:6c:39:77:27:92:de:61:c7:
                    b1:d3:a5:2f:ef:66:9b:f5:71:42:77:0a:d2:10:7f:50
$

И тут стало понятно, что не все так хорошо. Да, алгоритм подписи Digest Encryption Algorithm: GOST R 34.10-2012 Key 512 в соответствии с выбранным для подписи сертификатом, но подпись формируется от хэша, посчитанному по алгоритму SHA-256 (Digest Algorithm (1): SHA-256). А это неправильно с точки: хэш для GOST R 34.10-2012 Key 512 должен считаться по алгоритму ГОСТ Р 34.11-2012-512.

Приступаем а анализу исходного кода libreoffice: не так страшен черт как его малюют. В данной статье мы рассматриваем использование пакета NSS для формирования электронной подписи. Если кто предпочитает на платформе MS Windows, использовать CryptoAPI (и, соответственно, ГОСТ-CSP), может по аналогии с данным материалом сделать соответствующую доработку.

Анилиз показал, что правки придется внести всего в два файла:
~/libreoffice-5.3.7.2/vcl/source/gdi/pdfwriter_impl.cxx
~/libreoffice-5.3.7.2/xmlsecurity/source/pdfio/pdfdocument.cxx

Эти изменения связаны с правильным выбором хэш-функции для ГОСТ-овых сертификатов. Выбор хэш-функции будем определять в зависимости от типа ключа сертификата. Выбор хэш-алгоритма, например, в PDFWriter::Sign (файл pdfwriter_impl.cxx) будет выглядеть так:

bool PDFWriter::Sign(PDFSignContext& rContext)
{
#ifndef _WIN32
/*Добавленные переменные*/
    SECKEYPublicKey *pubk = NULL;
    SECOidTag hashAlgTag;
    HASH_HashType hashType;
    int hashLen;

    CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(rContext.m_pDerEncoded), rContext.m_nDerEncoded);

    if (!cert)
    {
        SAL_WARN("vcl.pdfwriter", "CERT_DecodeCertFromPackage failed");
        return false;
    }
/*Получаем из сертификата открытый ключ*/
    pubk = CERT_ExtractPublicKey(cert);
    if (pubk == NULL)
	return NULL;
/*Проверяем тип открытого ключа*/
    switch(pubk->keyType){
	case gost3410Key:
	    hashAlgTag = SEC_OID_GOSTHASH;
	    hashType = HASH_AlgGOSTHASH;
	    hashLen = SHA256_LENGTH;
	    break;
	case gost3410Key_256:
	    hashAlgTag = SEC_OID_GOST3411_2012_256;
	    hashType = HASH_AlgGOSTHASH_12_256;
	    hashLen = SHA256_LENGTH;
	    break;
	case gost3410Key_512:
	    hashAlgTag = SEC_OID_GOST3411_2012_512;
	    hashLen = SHA256_LENGTH * 2;
	    hashType = HASH_AlgGOSTHASH_12_512;
	    break;
	default:
	    hashAlgTag = SEC_OID_SHA256;
	    hashType = HASH_AlgSHA256;
	    hashLen = SHA256_LENGTH;
	    break;
    }
/*Вычисление хэш*/
    HashContextScope hc(HASH_Create(hashType));
. .  .
}

Остальные изменения по логике аналогичны этим. Патч для файла ~/libreoffice-5.3.7.2/vcl/source/gdi/pdfwriter_impl.cxx находится

здесь:
--- pdfwriter_impl_ORIG.cxx	2017-10-25 17:25:39.000000000 +0300
+++ pdfwriter_impl.cxx	2018-10-31 19:48:32.078482227 +0300
@@ -6698,6 +6698,9 @@
                                 CERTCertificate *cert,
                                 SECItem *digest)
 {
+    SECKEYPublicKey *pubk = NULL;
+    SECOidTag hashAlgTag;
+
     NSSCMSMessage *result = NSS_CMSMessage_Create(nullptr);
     if (!result)
     {
@@ -6732,8 +6735,31 @@
         NSS_CMSMessage_Destroy(result);
         return nullptr;
     }
-
+    pubk = CERT_ExtractPublicKey(cert);
+    if (pubk == NULL)
+	return NULL;
+    switch(pubk->keyType){
+	case gost3410Key:
+	    hashAlgTag = SEC_OID_GOSTHASH;
+fprintf(stderr, "CreateCMSMessage: gost3410Key Use HASH_AlgGOSTHASH_=%d\n", hashAlgTag);
+	    break;
+	case gost3410Key_256:
+	    hashAlgTag = SEC_OID_GOST3411_2012_256;
+fprintf(stderr, "CreateCMSMessage: gost3410Key_256 Use HASH_AlgGOSTHASH_=%d\n", hashAlgTag);
+	    break;
+	case gost3410Key_512:
+	    hashAlgTag = SEC_OID_GOST3411_2012_512;
+fprintf(stderr, "CreateCMSMessage: gost3410Key_512  Use HASH_AlgGOSTHASH_=%d\n", hashAlgTag);
+	    break;
+	default:
+	    hashAlgTag = SEC_OID_SHA256;
+	    break;
+    }
+/*
     *cms_signer = NSS_CMSSignerInfo_Create(result, cert, SEC_OID_SHA256);
+*/
+    *cms_signer = NSS_CMSSignerInfo_Create(result, cert, hashAlgTag);
+
     if (!*cms_signer)
     {
         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_Create failed");
@@ -6773,8 +6799,8 @@
         NSS_CMSMessage_Destroy(result);
         return nullptr;
     }
+    if (NSS_CMSSignedData_SetDigestValue(*cms_sd, hashAlgTag, digest) != SECSuccess)
 
-    if (NSS_CMSSignedData_SetDigestValue(*cms_sd, SEC_OID_SHA256, digest) != SECSuccess)
     {
         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_SetDigestValue failed");
         NSS_CMSSignedData_Destroy(*cms_sd);
@@ -6982,6 +7008,10 @@
 bool PDFWriter::Sign(PDFSignContext& rContext)
 {
 #ifndef _WIN32
+    SECKEYPublicKey *pubk = NULL;
+    SECOidTag hashAlgTag;
+    HASH_HashType hashType;
+    int hashLen;
 
     CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(rContext.m_pDerEncoded), rContext.m_nDerEncoded);
 
@@ -6990,8 +7020,33 @@
         SAL_WARN("vcl.pdfwriter", "CERT_DecodeCertFromPackage failed");
         return false;
     }
+    pubk = CERT_ExtractPublicKey(cert);
+    if (pubk == NULL)
+	return NULL;
+    switch(pubk->keyType){
+	case gost3410Key:
+	    hashAlgTag = SEC_OID_GOSTHASH;
+	    hashType = HASH_AlgGOSTHASH;
+	    hashLen = SHA256_LENGTH;
+	    break;
+	case gost3410Key_256:
+	    hashAlgTag = SEC_OID_GOST3411_2012_256;
+	    hashType = HASH_AlgGOSTHASH_12_256;
+	    hashLen = SHA256_LENGTH;
+	    break;
+	case gost3410Key_512:
+	    hashAlgTag = SEC_OID_GOST3411_2012_512;
+	    hashLen = SHA256_LENGTH * 2;
+	    hashType = HASH_AlgGOSTHASH_12_512;
+	    break;
+	default:
+	    hashAlgTag = SEC_OID_SHA256;
+	    hashType = HASH_AlgSHA256;
+	    hashLen = SHA256_LENGTH;
+	    break;
+    }
+    HashContextScope hc(HASH_Create(hashType));
 
-    HashContextScope hc(HASH_Create(HASH_AlgSHA256));
     if (!hc.get())
     {
         SAL_WARN("vcl.pdfwriter", "HASH_Create failed");
@@ -7005,15 +7060,18 @@
     HASH_Update(hc.get(), static_cast<const unsigned char*>(rContext.m_pByteRange2), rContext.m_nByteRange2);
 
     SECItem digest;
-    unsigned char hash[SHA256_LENGTH];
+    unsigned char hash[SHA256_LENGTH * 2];
+
     digest.data = hash;
-    HASH_End(hc.get(), digest.data, &digest.len, SHA256_LENGTH);
+    HASH_End(hc.get(), digest.data, &digest.len, hashLen);
+
     hc.clear();
 
 #ifdef DBG_UTIL
     {
         FILE *out = fopen("PDFWRITER.hash.data", "wb");
-        fwrite(hash, SHA256_LENGTH, 1, out);
+        fwrite(hash, hashLen, 1, out);
+
         fclose(out);
     }
 #endif
@@ -7078,8 +7136,8 @@
             fclose(out);
         }
 #endif
+        HashContextScope ts_hc(HASH_Create(hashType));
 
-        HashContextScope ts_hc(HASH_Create(HASH_AlgSHA256));
         if (!ts_hc.get())
         {
             SAL_WARN("vcl.pdfwriter", "HASH_Create failed");
@@ -7090,16 +7148,19 @@
         HASH_Begin(ts_hc.get());
         HASH_Update(ts_hc.get(), ts_cms_signer->encDigest.data, ts_cms_signer->encDigest.len);
         SECItem ts_digest;
-        unsigned char ts_hash[SHA256_LENGTH];
+        unsigned char ts_hash[SHA256_LENGTH * 2];
+
         ts_digest.type = siBuffer;
         ts_digest.data = ts_hash;
-        HASH_End(ts_hc.get(), ts_digest.data, &ts_digest.len, SHA256_LENGTH);
+        HASH_End(ts_hc.get(), ts_digest.data, &ts_digest.len, hashLen);
+
         ts_hc.clear();
 
 #ifdef DBG_UTIL
         {
             FILE *out = fopen("PDFWRITER.ts_hash.data", "wb");
-            fwrite(ts_hash, SHA256_LENGTH, 1, out);
+            fwrite(ts_hash, hashLen, 1, out);
+
             fclose(out);
         }
 #endif
@@ -7111,7 +7172,8 @@
 
         src.messageImprint.hashAlgorithm.algorithm.data = nullptr;
         src.messageImprint.hashAlgorithm.parameters.data = nullptr;
-        SECOID_SetAlgorithmID(nullptr, &src.messageImprint.hashAlgorithm, SEC_OID_SHA256, nullptr);
+        SECOID_SetAlgorithmID(nullptr, &src.messageImprint.hashAlgorithm, hashAlgTag, nullptr);
+
         src.messageImprint.hashedMessage = ts_digest;
 
         src.reqPolicy.type = siBuffer;
@@ -7340,11 +7402,13 @@
     // Write ESSCertIDv2.hashAlgorithm.
     aCertID.hashAlgorithm.algorithm.data = nullptr;
     aCertID.hashAlgorithm.parameters.data = nullptr;
-    SECOID_SetAlgorithmID(nullptr, &aCertID.hashAlgorithm, SEC_OID_SHA256, nullptr);
+    SECOID_SetAlgorithmID(nullptr, &aCertID.hashAlgorithm, hashAlgTag, nullptr);
+
     // Write ESSCertIDv2.certHash.
     SECItem aCertHashItem;
-    unsigned char aCertHash[SHA256_LENGTH];
-    HashContextScope aCertHashContext(HASH_Create(HASH_AlgSHA256));
+    unsigned char aCertHash[SHA256_LENGTH*2];
+    HashContextScope aCertHashContext(HASH_Create(hashType));
+
     if (!aCertHashContext.get())
     {
         SAL_WARN("vcl.pdfwriter", "HASH_Create() failed");
@@ -7354,7 +7418,8 @@
     HASH_Update(aCertHashContext.get(), reinterpret_cast<const unsigned char *>(rContext.m_pDerEncoded), rContext.m_nDerEncoded);
     aCertHashItem.type = siBuffer;
     aCertHashItem.data = aCertHash;
-    HASH_End(aCertHashContext.get(), aCertHashItem.data, &aCertHashItem.len, SHA256_LENGTH);
+    HASH_End(aCertHashContext.get(), aCertHashItem.data, &aCertHashItem.len, hashLen);
+
     aCertID.certHash = aCertHashItem;
     // Write ESSCertIDv2.issuerSerial.
     IssuerSerial aSerial;


Патч для файла ~/libreoffice-5.3.7.2/xmlsecurity/source/pdfio/pdfdocument.cxx находится

здесь:
--- pdfdocument_ORIG.cxx	2017-10-25 17:25:39.000000000 +0300
+++ pdfdocument.cxx	2018-10-31 19:49:34.174485641 +0300
@@ -2400,6 +2400,19 @@
     case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
         eOidTag = SEC_OID_SHA512;
         break;
+    case SEC_OID_GOST3410_SIGN_256:
+    case SEC_OID_GOST3411_2012_256:
+        eOidTag = SEC_OID_GOST3411_2012_256;
+	break;
+    case SEC_OID_GOST3410_SIGN_512:
+    case SEC_OID_GOST3411_2012_512:
+        eOidTag = SEC_OID_GOST3411_2012_512;
+	break;
+    case SEC_OID_GOST3410_SIGNATURE:
+    case SEC_OID_GOSTHASH:
+        eOidTag = SEC_OID_GOSTHASH;
+	break;
+
     default:
         break;
     }
@@ -2453,6 +2466,16 @@
     case SEC_OID_SHA512:
         nMaxResultLen = msfilter::SHA512_HASH_LENGTH;
         break;
+    case SEC_OID_GOST3411_2012_256:
+        nMaxResultLen = msfilter::SHA256_HASH_LENGTH;
+	break;
+    case SEC_OID_GOST3411_2012_512:
+        nMaxResultLen = msfilter::SHA512_HASH_LENGTH;
+	break;
+    case SEC_OID_GOSTHASH:
+        nMaxResultLen = msfilter::SHA256_HASH_LENGTH;
+	break;
+
     default:
         SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ValidateSignature: unrecognized algorithm");
         return false;


После внесения изменений проводим сборку пакета libreoffice. Внесенные изменения коснулись трех библиотек (/usr/lib64/libreoffice/program):

  • libvcllo.so;
  • libxmlsecurity.so;
  • libxsec-xmlsec.so

Именно эти три библиотеки были заменены в установленном дистрибутиве libreoffice (/usr/lib64/libreoffice/program).

После этого подписание и проверка ГОСТ-подписи в PDF-файлах прошла без сучка и задоринки. И тут на одном из сайтов попадается на глаза такая выдержка:
У Федеральной налоговой службы есть отличный сервис для получения выписки из ЕГРЮЛ для любого юридического лица, причем абсолютно бесплатно. Выписку можно получить в виде документа формата PDF, подписанном квалифицированной электронной подписью. И такую выписку можно отправить в коммерческий банк, госучреждение, и с вас не попросят ее в бумажном виде. В общем, очень удобно.
Заказываем, получаем и проверяем:



Стоит напомнить, что не следует забывать устанавливать в хранилище цепочку доверенных сертификатов для сертификата подписанта. Но это естественно.

Все, теперь есть возможность использования электронной подписи (одной или несколько) в PDF-файлах. Это очень удобно как при согласовании документов, так и хранении документов.

А если кто привык работать с классической электронной подписью в формате PKCS#7 как присоединенной, так и отсоединенной, то для них подготовлена обновленная версия (для платформы Linux и Windows) графического пакета GUINSSPY:



Разработка велась на Python3 и если на платформе Linux проблем не было, то на MS Windows пришлось попотеть с кодировками. Фактически это была отдельная разработка и это требует отдельной статьи. Все эти нюансы можно увидеть в исходном коде.

С помощью этой утилиты можно создать хранилище сертификатов для libreoffice, управлять сертификатами, подписывать файлы и т.д.:



Утилита также позволяет создать запрос на сертификат с генерацией ключевой пары, который затем можно передать в удостоверяющий центр, а полученный сертификат установить в хранилище:



И вот если производители отечественных форков Linux доработали различные пакеты (NSS, Firefox, Thunderbiird, GnuPG/SMIME, SSH, KMail, Kleopatra, LibreOffice, OpenSSL, и т.д и т.п.) для работы с российской криптографией, то тогда можно было бы говорить об импортозамещении в области криптографии.

Комментарии (14)


  1. Temmokan
    01.11.2018 07:27

    Любопытно, упомянутый сайт soft.lissi.ru принципиально не использует HTTPS? Чтобы, например, проще было подменить ответ сервера при скачивании софта и прочего?


    1. saipr Автор
      01.11.2018 09:02
      +2

      Нет, конечно, никакого принципа нет. HTTPS на ГОСТ защищает УЦ.
      Вы думаете есть желающие подменить? Надо будет сказать, чтобы все же подключили https.


      1. Temmokan
        01.11.2018 10:24

        Вряд ли такая гора желающих, просто выглядит странно — сайт по вопросам безопасности и всего такого, на чистом HTTP.


        1. saipr Автор
          01.11.2018 10:34

          Дело еше в том, если закрыть сайт HTTPS-ом, но ГОСТ-овым, то нанего мало кто попадет (понятно почему). А защищать сайт не ГОСТ-овым https, как-то некрасиво — проповедуете ГОСТ, а тут… Хотя все наши государственные сайты/порталы в своем большинстве, даже tk26, защищены не ГОСТ-ом:



          Я думаю этот недочет устраним.


          1. Temmokan
            01.11.2018 12:08

            Полагаю, что если выбор стоит между «вообще не защищать передачу от перехвата» и «использовать HTTPS, поддерживаемый самыми используемыми браузерами», ответ скорее в пользу второго.

            Тем более, что те же госуслуги используют международно принятый HTTPS (сертификат от COMODO CA Limited).


            1. saipr Автор
              01.11.2018 12:17

              Так-то оно так! COMODO хорошо. Но те же Госуслуги и ФНС выдают услуги по ГОСТ-сертификату. Получаются двойные стандарты.
              Может проще перейти на международно принятую криптографию?
              Вообще-то это нонсенс получать SSL-сертификат для ГОСУСЛУГ России где-то на Западе!


  1. mikekaganski
    01.11.2018 09:02
    +1

    И вот если производители отечественных форков Linux доработали различные пакеты


    А Вы не хотели бы внести указанные правки в LibreOffice самостоятельно? Достаточно отправить Code Contributor Statement, и разместить патч в геррит.


    1. saipr Автор
      01.11.2018 09:09
      +2

      А разве я несамостоятельно разбираюсь в коде LibreOffice или GnuPG и предлагаю правки?
      А чтоже делают наши производители "отечественных форков Linux" кроме капипаста? Сколько раз я им предлагал просто исправить ошибки (причем самые простые ), а в ответ ...


      А за наводку Спасибо.


      1. mikekaganski
        01.11.2018 11:02

        Насколько я знаю, предлагать правки в своём блоге или по почте чаще всего бессмысленно (хотя у некоторых проектов есть политика приёма патчей по почте). У проектов обычно есть своя политика приёма правок, и у многих это именно размещение патча в системе peer review. Поэтому как бы ни были хороши намерения, если не следовать установленным в проекте правилам, все полезные предложения могут оказаться потерянными в непредназначенном для этого канале.


        1. saipr Автор
          01.11.2018 11:16

          Конечно вы правы. Но прояснить откуда и зачем появляются эти правки все же надо.
          Да, а сами патчи отправить по назначению.


          1. mikekaganski
            01.11.2018 11:23
            +1

            Конкретно в случае ЛО практика такова:

            1. Создаётся багрепорт с описанием проблемы на английском языке («не работает подписание с использованием алгоритма такого-то; шаги для воспроизведения: 1, 2, 3...»).
            2. Отправляется патч в геррит, commit message которого в первой строке имеет тег tdf#XXXX, где XXXX — номер багрепорта. Ну, и конечно, commit message будет содержать достаточный объём информации (при необходимости — хоть «войну и мир»).

            Это позволяет привязать патч к объяснению «откуда и зачем», расширить обсуждение при необходимости (в баге или в геррите), и сохранить это обсуждение для «последующих поколений», которым понадобится контекст при будущих правках. Никакие нестандартные каналы не могут обеспечить такой преемственности.


            1. saipr Автор
              01.11.2018 11:29

              Огромное спасибо. Беру на проработку.


  1. amarao
    01.11.2018 13:35
    -1

    Последние скриншоты показывают проблемы со шрифтами. Во-первых, зачем шрифт с серифами (засечками) в интерфейсе? Серифы обычно используются на текстах для чтения, а не в навигации.

    Второе: почему такое количество шрифтов? Разве один шрифт в разных начертаниях не был бы лучше?

    … Всё даже страшнее, чем я думал. Одни и те же элементы управления могут показывать как штрифты с засечками, так и без. (кнопки «Отмена» и «завершаем», например).


    1. saipr Автор
      01.11.2018 14:25
      +1

      Почему страшнее?


      Несколько десятков лет в научных и типографических кругах не утихают споры, на первый взгляд, по незначительному вопросу: является ли шрифт с засечками более разборчивым, а шрифт без засечек, соответственно, менее четким для восприятия?
      По сей день никто не предоставил окончательного неоспоримого ответа на этот вопрос.

      Еще вопрос


      Второе: почему такое количество шрифтов?

      Только в учебных целях — показать как управлять шрифтами.


      Разве один шрифт в разных начертаниях не был бы лучше?

      Может и так, дело вкуса. Если вы запустили утилиту guinsspy (интересно на какой платформе windows или linux), значит вы получили и доступ к исходному коду утилиты и вам не составит труда выбрать шрифты по вашему вкусу. Спасибо.