PKI: مكتبات GCrypt و KSBA كبديل لـ OpenSSL مع دعم التشفير الروسي. استمرار

نواصل الحديث عن البديل لـ opensl وسنتحدث عن مكتبة libksba ، التي تعد جزءًا من GnuPG. توفر مكتبة libksba واجهة عالية المستوى للعمل مع كائنات البنية التحتية للمفتاح العام مثل الشهادات وطلبات الشهادة والتوقيع الإلكتروني (CMS / PKCS # 7). ومع ذلك ، على عكس مكتبة GCrypt ، التي تدعم خوارزميات التشفير الروسية ، تفتقر libksba إلى تنفيذ توصيات TK-26 حول استخدام GOST R 34.10-2001 / 2012 ، GOST R 34.11-94 / 2012 في كائنات PKI مثل الشهادات ، طلبات للحصول على شهادات ، كائنات PKCS # 7 / CMS (مستندات موقعة و / أو مشفرة ، إلخ).

دعنا نبدأ مع معرفات الهوية التي يمكن (أو ينبغي) أن تكون جزءًا من السمات المميزة DN (الاسم المميز) للمصدر (الناشر) وموضوع (مالك) الشهادة. في مكتبة libksba ، تتم كتابة oid s في بنية oid_name_tbl [] (ملف dn.c). لا تحتوي بنية oid_name_tbl [] على رقم OID لـ TIN و BIN و OGRNIP و SNILS الموصى بها بواسطة TK-26 للحصول على شهادة مؤهلة:
18 - وتشمل السمات الإضافية للاسم ، التي تحدد الحاجة إلى استخدامه وفقا للقانون الاتحادي ، ما يلي:

1) OGRN.
قيمة سمة OGRN هي سلسلة مكونة من 13 رقمًا تمثل OGRN لحامل شهادة مؤهلة - كيان قانوني. يحتوي معرف كائن نوع سمة OGRN على النموذج 1.2.643.100.1 ، ويتم وصف نوع سمة OGRN على النحو التالي: OGRN :: = NUMERIC STRING SIZE 13؛

2) SNILS (SNILS).
قيمة سمة SNILS هي سلسلة مكونة من 11 رقمًا تمثل SNILS لمالك الشهادة المؤهلة - فرد. معرف الكائن لنوع سمة SNILS هو 1.2.643.100.3 ، يتم وصف نوع سمة SNILS على النحو التالي: SNILS :: = NUMERIC STRING SIZE 11؛

3) INN.
قيمة السمة INN هي سلسلة مكونة من 12 رقمًا تمثل رقم التعريف الضريبي لحامل الشهادة المؤهلة. معرف كائن نوع سمة INN هو 1.2.643.3.131.1.1 ، يتم وصف نوع سمة INN على النحو التالي: INN :: = NUMERIC STRING SIZE 12.

بطبيعة الحال ، تحتاج إلى إضافة هذه الأواني:

static const struct { const char *name; int source; /* 0 = unknown 1 = rfc2253 2 = David Chadwick, July 2003 <draft-ietf-pkix-dnstrings-02.txt> 3 = Peter Gutmann 4 = tk26 */ const char *description; size_t oidlen; const unsigned char *oid; /* DER encoded OID. */ const char *oidstr; /* OID as dotted string. */ } oid_name_tbl[] = { {"CN", 1, "CommonName", 3, "\x55\x04\x03", "2.5.4.3" }, {"SN", 2, "Surname", 3, "\x55\x04\x04", "2.5.4.4" }, {"SERIALNUMBER", 2, "SerialNumber",3, "\x55\x04\x05", "2.5.4.5" }, {"C", 1, "CountryName", 3, "\x55\x04\x06", "2.5.4.6" }, {"L" , 1, "LocalityName", 3, "\x55\x04\x07", "2.5.4.7" }, {"ST", 1, "StateOrProvince", 3, "\x55\x04\x08", "2.5.4.8" }, {"STREET", 1, "StreetAddress", 3, "\x55\x04\x09", "2.5.4.9" }, {"O", 1, "OrganizationName", 3, "\x55\x04\x0a", "2.5.4.10" }, {"OU", 1, "OrganizationalUnit", 3, "\x55\x04\x0b", "2.5.4.11" }, {"T", 2, "Title", 3, "\x55\x04\x0c", "2.5.4.12" }, {"D", 3, "Description", 3, "\x55\x04\x0d", "2.5.4.13" }, {"BC", 3, "BusinessCategory", 3, "\x55\x04\x0f", "2.5.4.15" }, {"ADDR", 2, "PostalAddress", 3, "\x55\x04\x11", "2.5.4.16" }, {"POSTALCODE" , 0, "PostalCode", 3, "\x55\x04\x11", "2.5.4.17" }, {"GN", 2, "GivenName", 3, "\x55\x04\x2a", "2.5.4.42" }, {"PSEUDO", 2, "Pseudonym", 3, "\x55\x04\x41", "2.5.4.65" }, {"DC", 1, "domainComponent", 10, "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19", "0.9.2342.19200300.100.1.25" }, {"UID", 1, "userid", 10, "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x01", "0.9.2342.19200300.100.1.1 " }, {"E", 1, "emailAddress", 9, "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01", "1.2.840.113549.1.9.1" }, /*TK-26*/ {"OGRN", 4, "OGRN", 5, "\x2a\x85\x03\x64\x01", "1.2.643.100.1" }, {"INN", 4, "INN", 8, "\x2a\x85\x03\x03\x81\x03\x01\x01", "1.2.643.3.131.1.1" }, {"SNILS", 4, "SNILS", 5, "\x2a\x85\x03\x64\x03", "1.2.643.100.3" }, {"OGRNIP", 4, "OGRNIP", 5, "\x2a\x85\x03\x64\x05", "1.2.643.100.5" }, { NULL } }; 

ما هو جدير بالملاحظة في هذا الهيكل هو وجود حقل المصدر ، الذي يشير إلى من دخل حقل معين ، على سبيل المثال ، 1 (وحدة) تشير إلى أن الحقل محدد في rfc2253 ، و 4 (أربعة) المضافة هنا ستكون تشير إلى أن المجال أوصت به اللجنة الفنية TK-26. وفقًا لتوصيات TK-26 ، تعد سمات TIN و OGRN و OGRNIP و SNILS من النوع NUMERIC STRING (انظر أعلاه). يتم توفير معالجة الأويضات المدرجة في الاسم المميز في libksba في وظيفة append_atv (ملف dn.c) ، ومع ذلك ، فهي تفتقر إلى معالجة النوع TYPE_NUMERIC_STRING ، ويجب عليك إضافتها:

 . . . switch (use_hex? 0 : node->type) { case TYPE_UTF8_STRING: append_utf8_value (image+node->off+node->nhdr, node->len, sb); break; /*   NUMERIC STRING*/ case TYPE_NUMERIC_STRING: case TYPE_PRINTABLE_STRING: …. 

التصحيح لملف dn.c هنا:
 --- dn_ORIG.c 2016-08-22 11:40:58.000000000 +0300 +++ dn.c 2018-06-26 19:23:38.068492230 +0300 @@ -48,6 +48,7 @@ 2 = David Chadwick, July 2003 <draft-ietf-pkix-dnstrings-02.txt> 3 = Peter Gutmann + 4 = tk26 */ const char *description; size_t oidlen; @@ -74,12 +75,17 @@ "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19", "0.9.2342.19200300.100.1.25" }, {"UID", 1, "userid", 10, "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x01", "0.9.2342.19200300.100.1.1 " }, -{"EMAIL", 3, "emailAddress", 9, +{"E", 1, "emailAddress", 9, "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01", "1.2.840.113549.1.9.1" }, +/*oid-    TK-26*/ +{"OGRN", 4, "OGRN", 5, "\x2a\x85\x03\x64\x01", "1.2.643.100.1" }, +{"INN", 4, "INN", 8, "\x2a\x85\x03\x03\x81\x03\x01\x01", "1.2.643.3.131.1.1" }, +{"SNILS", 4, "SNILS", 5, "\x2a\x85\x03\x64\x03", "1.2.643.100.3" }, +{"OGRNIP", 4, "OGRNIP", 5, "\x2a\x85\x03\x64\x05", "1.2.643.100.5" }, + { NULL } }; - #define N 0x00 #define P 0x01 static unsigned char charclasses[128] = { @@ -555,8 +561,8 @@ name = NULL; for (i=0; oid_name_tbl[i].name; i++) { - if (oid_name_tbl[i].source == 1 - && node->len == oid_name_tbl[i].oidlen +/* oid-  DN    */ + if (node->len == oid_name_tbl[i].oidlen && !memcmp (image+node->off+node->nhdr, oid_name_tbl[i].oid, node->len)) { @@ -604,6 +610,9 @@ case TYPE_UTF8_STRING: append_utf8_value (image+node->off+node->nhdr, node->len, sb); break; +/*  NUMERIC_STRING*/ + case TYPE_NUMERIC_STRING: + case TYPE_PRINTABLE_STRING: case TYPE_IA5_STRING: /* we assume that wrong encodings are latin-1 */ 


احفظه في ملف diff_dn.patch.
يمكن تنزيل مكتبة libksba من هنا . قم بفك ضغط الأرشيف ، أدخل دليل src وقم بتطبيق patch diff_dn.patch على ملف dn.c:

 $patch dn.c < diff_dn.patch $ 

بالإضافة إلى Oids لسمات DN ، من الضروري أيضًا إضافة Oids لمفاتيح GOST إلى بنية pk_algo_table [] (key keyfofo.c):
 static const struct algo_table_s pk_algo_table[] = { { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.1 */ "1.2.840.113549.1.1.1", /* rsaEncryption (RSAES-PKCA1-v1.5) */ "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01", 9, 1, PKALGO_RSA, "rsa", "-ne", "\x30\x02\x02" }, . . . /* oid- - */ { /* GOST3410-2001 */ "1.2.643.2.2.19", /* gostPublicKey-2001 */ "\x2a\x85\x03\x02\x02\x13", 6, 1, PKALGO_ECC, "ecc", "q", "\x80" }, { /* GOST3410-2012-256 */ "1.2.643.7.1.1.1.1", /* gostPublicKey-2012-256 */ "\x2a\x85\x03\x07\x01\x01\x01\x01", 8, 1, PKALGO_ECC, "ecc", "q", "\x80" }, { /* GOST3410-2012-512 */ "1.2.643.7.1.1.1.2", /* gostPublicKey-2012-512 */ "\x2a\x85\x03\x07\x01\x01\x01\x02", 8, 1, PKALGO_ECC, "ecc", "q", "\x80" }, {NULL} }; 

وبالمثل ، في بنية sig_algo_table [] (ملف keyihfo.c) ، نضيف OID-s المرتبط بالتوقيع الإلكتروني وفقًا لـ GOST:

 static const struct algo_table_s sig_algo_table[] = { { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.5 */ "1.2.840.113549.1.1.5", /* sha1WithRSAEncryption */ "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05", 9, 1, PKALGO_RSA, "rsa", "s", "\x82", NULL, NULL, "sha1" }, . . . /*oid-,   - */ { /* GOST3410-2001 */ "1.2.643.2.2.19", /* gostPublicKey-2001 */ "\x2a\x85\x03\x02\x02\x13", 6, 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "gostr3411_CP" }, { /* GOST3410-2012-256 */ "1.2.643.7.1.1.1.1", /* gostPublicKey-2012-256 */ "\x2a\x85\x03\x07\x01\x01\x01\x01", 8, 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog256"}, { /* GOST3410-2012-512 */ "1.2.643.7.1.1.1.2", /* gostPublicKey-2012-512 */ "\x2a\x85\x03\x07\x01\x01\x01\x02", 8, 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog512"}, { /* GOST3411-2012-256 */ "1.2.643.7.1.1.3.2", /* STRIBOG256 */ "\x2a\x85\x03\x07\x01\x01\x03\x02", 8, 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog256" }, { /* GOST3411-2012-512 */ "1.2.643.7.1.1.3.3", /* STRIBOG512 */ "\x2a\x85\x03\x07\x01\x01\x03\x03", 8, 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog512" }, { /* GOST3410-2001-Signature */ "1.2.643.2.2.3", /* gosrPublicKey-2001 avec signature */ "\x2a\x85\x03\x02\x02\x03", 6, 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "gostr3411_CP" }, {NULL} }; 

وأخيرًا ، نكمل بنية enc_algo_table [] مع الأغطية من مفاتيح GOST التي يمكن أن تشارك في التشفير غير المتماثل (PKCS # 7):

 static const struct algo_table_s enc_algo_table[] = { { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.1 */ "1.2.840.113549.1.1.1", /* rsaEncryption (RSAES-PKCA1-v1.5) */ "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", 9, 1, PKALGO_RSA, "rsa", "a", "\x82" }, { "1.2.643.2.2.19", /*GOST R34.10-2001 */ "\x2A\x85\x03\x02\x02\x13", 6, 1, PKALGO_ECC, "ecc", "a", "\x80" }, { "1.2.643.7.1.1.1.1", /*GOST R34.10-2012-256 */ "\x2A\x85\x03\x07\x01\x01\x01\x01", 8, 1, PKALGO_ECC, "ecc", "a", "\x80" }, { "1.2.643.7.1.1.1.2", /*GOST R34.10-2012-512 */ "\x2A\x85\x03\x07\x01\x01\x01\x02", 8, 1, PKALGO_ECC, "ecc", "a", "\x80" }, {NULL} }; 

الآن بعد أن قررنا على OID ، دعنا ننتقل إلى هيكل تخزين المفتاح العام في الشهادة. بشكل عام ، تحتوي بنية SubjectPublicKeyInfo في الشهادة على النموذج التالي:
 SubjectPublicKeyInfo ::= SEQUENCE { algorithm OBJECT IDENTIFIER GostR3410-2001/2012-PublicKeyParameters ::= SEQUENCE { publicKeyParamSet OBJECT IDENTIFIER, digestParamSet OBJECT IDENTIFIER, encryptionParamSet OBJECT IDENTIFIER } subjectKey BIT STRING } 
تحدد المعلمة publicKeyParamSet معرف نقطة المنحنى البيضاوي. يتم تسجيل نقاط Oid للنقاط المسموح بها في بنية بنية curve_aliases [] في ملف ecc_curves.c بمكتبة libgcrypt. في مكتبة libksba ، يتم تسجيل OID-S في هيكل البنية curve_names [] في ملف keyinfo.c. في هذا الهيكل ، يتم حذف الأوسمة "1.2.643.2.2.36.0" (GOST2001-CryptoPro-XchA) و "1.2.643.2.2.36.1" (GOST2001-CryptoPro-XchB). نضيف هذه الأويدات ، ولكن مع الأخذ في الاعتبار حقيقة أن OID "1.2.643.2.2.36.0" هو في الواقع نقطة مع OID "1.2.643.2.2.35.1" ، و "1.2.643.2.2.36.1" يتوافق مع oid "1.2.643.2.2.35.3":

 static const struct { const char *oid; const char *name; } curve_names[] = { { "1.3.6.1.4.1.3029.1.5.1", "Curve25519" }, . . . { "1.2.643.2.2.35.3", "GOST2001-CryptoPro-C" }, /* oid-*/ // "GOST2001-CryptoPro-XchA" { "1.2.643.2.2.36.0", "GOST2001-CryptoPro-A" }, // "GOST2001-CryptoPro-XchB" { "1.2.643.2.2.36.1", "GOST2001-CryptoPro-C" }, . . . } 

يتم حذف المعلمة encryptionParamSet بشكل عام. يمكن أيضًا حذف معلمة digestParamSet: يحدد نوع مفتاح GOST بشكل فريد digestParamSet.

يضاف إلى الوظيفة _ksba_keyinfo_to_sexp (ملف keyinfo.c) ، الكود المسؤول عن تعبئة توقيع GOST في متغير S إلى الكود الذي يستخرج المفتاح العام GOST من الشهادة ، ويوزعه ، ويحزمه في متغير S. crypt_val_to_sexp. يتم توفير التعليمات البرمجية مع التعليقات ولا تتطلب توضيحات إضافية. تحدثنا عن ميزات تخزين المفتاح العام والتوقيع في الشهادة في مقال سابق .

التصحيح لملف keyinfo.c هنا:
 --- keyinfo_ORIG.c 2015-10-28 13:41:48.000000000 +0300 +++ keyinfo.c 2018-06-29 10:22:38.312284306 +0300 @@ -45,7 +45,6 @@ #include "convert.h" #include "ber-help.h" - /* Constants used for the public key algorithms. */ typedef enum { @@ -98,6 +97,19 @@ "1.2.840.10045.2.1", /* ecPublicKey */ "\x2a\x86\x48\xce\x3d\x02\x01", 7, 1, PKALGO_ECC, "ecc", "q", "\x80" }, +/*oid- - */ + { /* GOST3410-2001 */ + "1.2.643.2.2.19", /* gostPublicKey-2001 */ + "\x2a\x85\x03\x02\x02\x13", 6, + 1, PKALGO_ECC, "ecc", "q", "\x80" }, + { /* GOST3410-2012-256 */ + "1.2.643.7.1.1.1.1", /* gostPublicKey-2012-256 */ + "\x2a\x85\x03\x07\x01\x01\x01\x01", 8, + 1, PKALGO_ECC, "ecc", "q", "\x80" }, + { /* GOST3410-2012-512 */ + "1.2.643.7.1.1.1.2", /* gostPublicKey-2012-512 */ + "\x2a\x85\x03\x07\x01\x01\x01\x02", 8, + 1, PKALGO_ECC, "ecc", "q", "\x80" }, {NULL} }; @@ -209,6 +221,32 @@ "1.3.36.3.4.3.2.2", /* sigS_ISO9796-2rndWithrsa_ripemd160 */ "\x2B\x24\x03\x04\x03\x02\x02", 7, 0, PKALGO_RSA, "rsa", "s", "\x82", NULL, NULL, "rmd160" }, +/*oid-,   - */ + { /* GOST3410-2001 */ + "1.2.643.2.2.19", /* gostPublicKey-2001 */ + "\x2a\x85\x03\x02\x02\x13", 6, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "gostr3411_94" }, + { /* GOST3410-2012-256 */ + "1.2.643.7.1.1.1.1", /* gostPublicKey-2012-256 */ + "\x2a\x85\x03\x07\x01\x01\x01\x01", 8, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog256"}, + { /* GOST3410-2012-512 */ + "1.2.643.7.1.1.1.2", /* gostPublicKey-2012-512 */ + "\x2a\x85\x03\x07\x01\x01\x01\x02", 8, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog512"}, + + { /* GOST3411-2012-256 */ + "1.2.643.7.1.1.3.2", /* STRIBOG256 */ + "\x2a\x85\x03\x07\x01\x01\x03\x02", 8, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog256" }, + { /* GOST3411-2012-512 */ + "1.2.643.7.1.1.3.3", /* STRIBOG512 */ + "\x2a\x85\x03\x07\x01\x01\x03\x03", 8, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog512" }, + { /* GOST3410-2001-Signature */ + "1.2.643.2.2.3", /* gosrPublicKey-2001 avec signature */ + "\x2a\x85\x03\x02\x02\x03", 6, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "gostr3411_94" }, {NULL} }; @@ -218,6 +256,20 @@ "1.2.840.113549.1.1.1", /* rsaEncryption (RSAES-PKCA1-v1.5) */ "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", 9, 1, PKALGO_RSA, "rsa", "a", "\x82" }, +/*oid- -    */ + { + "1.2.643.2.2.19", /*GOST R34.10-2001 */ + "\x2A\x85\x03\x02\x02\x13", 6, + 1, PKALGO_ECC, "ecc", "a", "\x80" }, + { + "1.2.643.7.1.1.1.1", /*GOST R34.10-2012-256 */ + "\x2A\x85\x03\x07\x01\x01\x01\x01", 8, + 1, PKALGO_ECC, "ecc", "a", "\x80" }, + { + "1.2.643.7.1.1.1.2", /*GOST R34.10-2012-512 */ + "\x2A\x85\x03\x07\x01\x01\x01\x02", 8, + 1, PKALGO_ECC, "ecc", "a", "\x80" }, + {NULL} }; @@ -267,6 +319,13 @@ { "1.2.643.2.2.35.1", "GOST2001-CryptoPro-A" }, { "1.2.643.2.2.35.2", "GOST2001-CryptoPro-B" }, { "1.2.643.2.2.35.3", "GOST2001-CryptoPro-C" }, +/* oid-       34.10-2001/2012*/ +// "GOST2001-CryptoPro-XchA" + { "1.2.643.2.2.36.0", "GOST2001-CryptoPro-A" }, +// "GOST2001-CryptoPro-XchB" + { "1.2.643.2.2.36.1", "GOST2001-CryptoPro-C" }, + + { "1.2.643.7.1.2.1.2.1", "GOST2012-tc26-A" }, { "1.2.643.7.1.2.1.2.2", "GOST2012-tc26-B" }, @@ -393,7 +452,8 @@ /* get the object identifier */ if (!derlen) return gpg_error (GPG_ERR_INV_KEYINFO); - c = *der++; derlen--; + c = *der++; + derlen--; if ( c != 0x06 ) return gpg_error (GPG_ERR_UNEXPECTED_TAG); /* not an OBJECT IDENTIFIER */ TLV_LENGTH(der); @@ -418,6 +478,7 @@ if (!derlen) return gpg_error (GPG_ERR_INV_KEYINFO); c = *der++; derlen--; + if ( c == 0x05 ) { /*printf ("parameter: NULL \n"); the usual case */ @@ -471,6 +532,7 @@ else { /* printf ("parameter: with tag %02x - ignored\n", c); */ + TLV_LENGTH(der); seqlen -= der - startparm; /* skip the value */ @@ -692,6 +754,9 @@ const unsigned char *ctrl; const char *elem; struct stringbuf sb; +/*XXXXX*/ + int gost_key; + char *parm_oid_hash = NULL; *r_string = NULL; @@ -701,6 +766,7 @@ c = *der++; derlen--; if ( c != 0x30 ) return gpg_error (GPG_ERR_UNEXPECTED_TAG); /* not a SEQUENCE */ + TLV_LENGTH(der); /* and now the inner part */ err = get_algorithm (1, der, derlen, &nread, &off, &len, &is_bitstr, @@ -715,13 +781,36 @@ && !memcmp (der+off, pk_algo_table[algoidx].oid, len)) break; } + if (!pk_algo_table[algoidx].oid) return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM); if (!pk_algo_table[algoidx].supported) return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); +/*   1 - - */ + gost_key = !memcmp(pk_algo_table[algoidx].oidstring, "1.2.643", 7); if (parm_off && parm_len && parm_type == TYPE_OBJECT_ID) parm_oid = ksba_oid_to_str (der+parm_off, parm_len); + else +/*  - */ + if (parm_off && parm_len && parm_type == TYPE_SEQUENCE && gost_key && (*(der+parm_off + off - 2) == TYPE_OBJECT_ID)){ +/* oid curve  -*/ + int len_hash; + int len_curve; + unsigned char* addr_hash; + unsigned char* addr_curve; + len_curve = (int) *(der+parm_off + off -1); + addr_curve = der+parm_off + off; + parm_oid = ksba_oid_to_str (addr_curve, len_curve); +/* oid   -*/ + if( *(addr_curve + len_curve)== TYPE_OBJECT_ID) { + len_hash = (unsigned int) *(der+parm_off + off + len_curve + 1); + addr_hash = addr_curve + len_curve + 2; + parm_oid_hash = ksba_oid_to_str (addr_hash, len_hash); + } +/* oid    -*/ + } + else if (parm_off && parm_len) { parmder = der + parm_off; @@ -762,6 +851,13 @@ put_stringbuf_sexp (&sb, "curve"); put_stringbuf_sexp (&sb, parm_oid); put_stringbuf (&sb, ")"); +/* oid-  - */ + if(gost_key && parm_oid_hash) { + put_stringbuf (&sb, "("); + put_stringbuf_sexp (&sb, "hash"); + put_stringbuf_sexp (&sb, parm_oid_hash); + put_stringbuf (&sb, ")"); + } } /* If parameters are given and we have a description for them, parse @@ -851,6 +947,43 @@ put_stringbuf (&sb, "("); tmp[0] = *elem; tmp[1] = 0; put_stringbuf_sexp (&sb, tmp); +/*        TK-26*/ + if(gost_key){ + unsigned char pk[129]; + unsigned char *x; + unsigned char *y; + int len_pk; + int len_xy; + int i; + unsigned char c_inv; + int offset; + pk[0] = 0x04; + if(len == 131 || len == 66){ + offset = 0; + if(der[0] == 0x04 && der[1] & 0x80) + offset = 3; + else if(der[0] == 0x04 && der[1] & 0x40) + offset = 2; + len_pk = len - offset; + memcpy(&pk[1], der + offset, len_pk); + x = &pk[1]; + len_xy = len_pk / 2; + y = x + len_xy; +/*REVERT-INVERTIROVANIE*/ + for (i = 0; i < (len_xy/2); i++) { + c_inv = *(x + i); + *(x + i) = *(x + len_xy - i - 1); + *(x + len_xy - i - 1) = c_inv; + } + for (i = 0; i < (len_xy/2); i++) { + c_inv = y[i]; + y[i] = y[len_xy - i -1]; + y[len_xy - i - 1] = c_inv; + } + put_stringbuf_mem_sexp (&sb, pk , len_pk + 1); + } + } else + put_stringbuf_mem_sexp (&sb, der, len); der += len; derlen -= len; @@ -1606,6 +1739,8 @@ const unsigned char *ctrl; const char *elem; struct stringbuf sb; +/*XXXXX*/ + int gost_sign; /* FIXME: The entire function is very similar to keyinfo_to_sexp */ *r_string = NULL; @@ -1615,7 +1750,6 @@ else algo_table = enc_algo_table; - err = get_algorithm (1, der, derlen, &nread, &off, &len, &is_bitstr, NULL, NULL, NULL); if (err) @@ -1628,11 +1762,16 @@ && !memcmp (der+off, algo_table[algoidx].oid, len)) break; } + if (!algo_table[algoidx].oid) return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM); + if (!algo_table[algoidx].supported) return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); +/*    oid-*/ + gost_sign = !memcmp(algo_table[algoidx].oidstring, "1.2.643", 7); + der += nread; derlen -= nread; @@ -1682,8 +1821,22 @@ put_stringbuf (&sb, "("); tmp[0] = *elem; tmp[1] = 0; +/*   ,  r  ,  s   */ + if(gost_sign == 1 && algo_table == sig_algo_table){ + put_stringbuf_sexp (&sb, "r"); + put_stringbuf_mem_sexp (&sb, der+(len/2), len/2); + put_stringbuf (&sb, ")"); + put_stringbuf (&sb, "("); + put_stringbuf_sexp (&sb, "s"); + put_stringbuf_mem_sexp (&sb, der, len/2); + } + else{ + put_stringbuf_sexp (&sb, tmp); put_stringbuf_mem_sexp (&sb, der, len); +/* */ + } + der += len; derlen -= len; put_stringbuf (&sb, ")"); 


احفظه في ملف diff_keyinfo.patch وقم بتطبيقه على ملف keyinfo.c:

 $patch keyinfo.c < diff_keyinfo.patch $ 

بعد إضافة هذه التصحيحات ، يمكنك بناء المكتبة. إذا كنت لن تقوم بتثبيت مكتبة libksba.so.8.11.6 المجمعة في النظام ، ولكنك ستستخدمها فقط للاختبار ، فمن المناسب نسخها إلى الدليل الذي سيتم فيه تجميع حالات الاختبار. هذه التصحيحات كافية لتحليل الشهادات باستخدام مفاتيح GOST ، بالإضافة إلى المستندات الموقعة بمفاتيح GOST بتنسيق PKCS # 7 ، واستخراج والتحقق من الصلاحية الرياضية للتوقيع الإلكتروني لشهادة X509 أو التوقيع الإلكتروني لمستند PKCS # 7 / CMS.

لاختبار ذلك ، ضع في اعتبارك وحدتي برامج. تتحقق الوحدة النمطية check_cert الأولى من توقيع الشهادة بشكل صحيح ، وتتحقق الوحدة check_cms_signed الثانية من سلامة المستند الموقع (CMS / PKCS # 7) وصحة توقيع المستند. تذكر أن صلاحية الشهادة لا تتحدد فقط بصحة توقيعها ، ولكن أيضًا بصحتها (عدم الاستدعاء) في الوقت الذي يتم التحقق منه. وبنفس الطريقة ، فإن صلاحية التوقيع بموجب وثيقة ما لا تتحدد فقط من خلال الموثوقية الرياضية للتوقيع ، ولكن أيضًا من خلال صحة شهادة التوقيع.

الصورة لإنشاء مستند موقع بتنسيق PKCS # 7 ، يمكنك استخدام الأداة guinss.exe المكتوبة بلغة Python مع Tkinter ، واستخدام الرموز المميزة PKCS # 11 مع دعم التشفير الروسي كوسيلة لحماية معلومات التشفير (SKZI):



نلاحظ أيضًا أن تنسيق PKCS # 7 قيد النظر في التوقيع الإلكتروني للمستند يعني ضمناً تضمين الموقّع في التوقيع. يتم ذلك حتى لا يصبح المثال هائلاً.

الكود المصدر لأداة التحقق من توقيع شهادة check_cert.c موضح هنا:
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <errno.h> #include <ctype.h> #include <gcrypt.h> #include <ksba.h> /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) /*  S-*/ static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } /*    */ static gpg_error_t check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) { gpg_error_t err; const char *algoid; gcry_md_hd_t md; int i, algo; ksba_sexp_t p; size_t n; /*     : S_PKEY - S-   . S_SIG - S-   S_HASH - S-     tbs- */ gcry_sexp_t s_sig, s_hash, s_pkey; const char *s; char algo_name[16+1]; /* hash algorithm name converted to lower case. */ int digestlen; unsigned char *digest; int gost_key; /* Hash the target certificate using the algorithm from that certificate. */ algoid = ksba_cert_get_digest_algo (cert); algo = gcry_md_map_name (algoid); if (!algo) { fprintf(stderr, "unknown hash algorithm `%s'\n", algoid? algoid:"?"); return (-1); } /*  */ gost_key = !memcmp(algoid, "1.2.643", 7); s = gcry_md_algo_name (algo); for (i=0; *s && i < sizeof algo_name - 1; s++, i++) algo_name[i] = tolower (*s); algo_name[i] = 0; err = gcry_md_open (&md, algo, 0); if (err) { fprintf(stderr, "md_open failed: %s\n", algoid); return err; } err = ksba_cert_hash (cert, 1, HASH_FNC, md); if (err) { fprintf(stderr, "ksba_cert_hash failed: %s\n", algoid); gcry_md_close (md); return err; } gcry_md_final (md); /*     */ p = ksba_cert_get_sig_val (cert); /*   */ n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) { gcry_md_close (md); ksba_free (p); return (-1); } /*   S-  libgcrypt*/ err = gcry_sexp_sscan ( &s_sig, NULL, p, n); ksba_free (p); if (err) { fprintf(stderr, "gcry_sexp_scan failed: %s\n", "Beda"); gcry_md_close (md); return err; } /* S- */ show_sexp ("Sig value:\n", s_sig); /*      */ p = ksba_cert_get_public_key (issuer_cert); n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) { fprintf(stderr, "libksba did not return a proper S-Exp\n"); gcry_md_close (md); ksba_free (p); gcry_sexp_release (s_sig); return (-1); } err = gcry_sexp_sscan ( &s_pkey, NULL, p, n); ksba_free (p); if (err) { fprintf(stderr, "gcry_sexp_scan failed: %s\n", "pubkey"); gcry_md_close (md); gcry_sexp_release (s_sig); return err; } /* S-   */ show_sexp ("s_pkey:\n", s_pkey); digestlen = gcry_md_get_algo_dlen (algo); digest = gcry_md_read (md, algo); if (gost_key){ unsigned char *h; unsigned char c; int len_xy; /*   littlt-endian  big-endian*/ unsigned short arch = 1; /* 0x0001 */ h = digest; len_xy = *((unsigned char *) &arch) == 0 ? 0:gcry_md_get_algo_dlen (algo); /* */ for (i = 0; i < (len_xy/2); i++) { c = *(h + i); *(h + i) = *(h + len_xy - i - 1); *(h + len_xy - i - 1) = c; } } switch (gost_key) { case 0: if ( gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))", algo_name, (int)digestlen, digest) ) { exit (1); } break; case 1: if ( gcry_sexp_build (&s_hash, NULL, "(data(flags gost)(value %b))", (int)digestlen, digest) ) { exit (1); } break; default: exit (1); } /* S-   tbs-*/ show_sexp ("s_hash:\n", s_hash); /* */ err = gcry_pk_verify (s_sig, s_hash, s_pkey); /* */ gcry_md_close (md); gcry_sexp_release (s_sig); gcry_sexp_release (s_hash); gcry_sexp_release (s_pkey); return err; } int main (int argc, unsigned char *argv[]) { FILE *fp; ksba_reader_t r; ksba_cert_t cert; FILE *fp_ca; ksba_reader_t r_ca; ksba_cert_t cert_ca; gpg_error_t err; unsigned char *sub_dn; if(argc != 3) { fprintf(stderr, "Usage: check_cert < > < >\n"); exit(1); } fp = fopen (argv[1], "rb"); if (!fp) { fprintf (stderr, "check_cert: can't open `%s'\n", argv[1]); exit (1); } err = ksba_reader_new (&r); if (err) { fprintf(stderr, "ksba_reader_new error\n"); exit(1); } err = ksba_reader_set_file (r, fp); if (err) { fprintf(stderr, "ksba_reader_set error\n"); exit(1); } err = ksba_cert_new (&cert); if (err){ fprintf(stderr, "ksba_cert_new error\n"); exit(1); } err = ksba_cert_read_der (cert, r); if (err){ fprintf(stderr, "ksba_cert_read_der error\n"); exit(1); } fp_ca = fopen (argv[2], "rb"); if (!fp_ca) { fprintf (stderr, "check_cert: can't open `%s'\n", argv[2]); exit (1); } err = ksba_reader_new (&r_ca); if (err) { fprintf(stderr, "ksba_reader_new error\n"); exit(1); } err = ksba_reader_set_file (r_ca, fp_ca); if (err) { fprintf(stderr, "ksba_reader_set error\n"); exit(1); } err = ksba_cert_new (&cert_ca); if (err){ fprintf(stderr, "ksba_cert_new error\n"); exit(1); } err = ksba_cert_read_der (cert_ca, r_ca); if (err){ fprintf(stderr, "ksba_cert_read_der error\n"); exit(1); } sub_dn = ksba_cert_get_subject (cert, 0); fprintf(stderr, "check_cert: Verify %s\n", sub_dn); err = check_cert_sig (cert_ca, cert); if (err) { fprintf(stderr, "check_cert: verify %s error\n", argv[1]); } else { fprintf(stderr, "check_cert: verify %s Ok\n", argv[1]); } } 


نقوم بحفظ الكود في ملف check_cert.c وترجمته وتشغيله:

 bash-4.3$ln –s libksba.so.8 lgcrypt libksba.so.8.11.6 bash-4.3$ cc -o check_cert check_cert.c -lgcrypt libksba.so.8.11.6 bash-4.3$ ./check_cert Usage: check_cert < > < > bash-4.3$ 

لذلك ، من أجل التحقق من الشهادة ، من الضروري الحصول على الشهادة نفسها وشهادة المرجع المصدق (على سبيل المثال ، يمكنك أخذها من المقالة السابقة) التي تم إصدارها عليها. يجب أن تكون الشهادات (في الوقت الحالي) مشفرة بـ DER:

 bash-4.3$ ./check_cert CERT_CMS_KSBA.der CAcert_NEWCA.der check_cert: Verify SNILS=22222222222,INN=123456789012,O=CMS,STREET=PKCS7,L= ,ST=50  ,C=RU,GN=KSBA,SN=GCrypt,CN= GCrypt and KSBA,E=test@test.ru Sig value: (sig-val (gost (r #FBD2976F7E63D792A695D4EB8D41F4880F43BB98108ABC313C1661380A1E480C54F96BBE611BA3D7ECB029E4C5685792D8D565AEA2E9AFD3AB660453C04EEC20#) (s #ACC68AC42AA2293A945E565C621AFF8F19AA5D5039D83D11D7125469DF068B1E0C4247A325CE031E9A9C31F55191CE4FB6528A11F0D81BE5463C38C30A2AD8AC#) ) (hash stribog512) ) s_pkey: (public-key (ecc (curve "1.2.643.7.1.2.1.2.1") (hash "1.2.643.7.1.1.2.3") (q #04C5BFDFB8481951FB19AE8631B27CD13979FAE1ED61910EF9E8A9EAC5D757503264C327C753D4E38E402434119806088E81E2C1D5FBD36FA43366BFE374367585DC6A79954EC97F796CF63CB2F23392050ECB50E147B80749927979057DD5CFD496A2C8A4367DDD0E0E92045147AB801EF177C3EB441979A2757377E982E93314#) ) ) s_hash: (data (flags gost) (value #B2507D0208DB58DE0FA9EF6E4A2EDD07E86BAD313C2A0546C786FD5CF16A515DF28A1B40149F95570A8943922D1C6CFDD781727070034FEC799C1EEB6611EBA0#) ) check_cert: verify CERT_CMS_KSBA.der Ok bash-4.3$ 

للتحقق من شهادة موقعة ذاتيًا ، يشار إلى الأخيرة على أنها شهادة تم التحقق منها وشهادة جذر:

 bash-4.3$ ./check_cert CAcert_NEWCA.der CAcert_NEWCA.der check_cert: Verify E=info@ooo.ru,CN= ,OU= 2,O= ,C=RU,ST= ,L=.  . . . check_cert: verify CAcert_NEWCA.der Ok bash-4.3$ 

لذلك لدينا أداة بسيطة للتحقق من توقيع الشهادات.

للتحقق من التوقيع الإلكتروني للوثائق في شكل PKCS # 7 وضعت

اختبار الأداة المساعدة check_cms_signed.c:
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <time.h> #include <errno.h> #include <ksba.h> //#include "t-common.h" #include <gcrypt.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) void dump_isotime (const ksba_isotime_t t) { if (!t || !*t) fprintf (stderr, "[none]"); else fprintf (stderr,"%.4s-%.2s-%.2s %.2s:%.2s:%s", t, t+4, t+6, t+9, t+11, t+13); } static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } void dummy_hash_fnc (void *arg, const void *buffer, size_t length) { (void)arg; (void)buffer; (void)length; } static int dummy_writer_cb (void *cb_value, const void *buffer, size_t count) { (void)cb_value; (void)buffer; (void)count; return 0; } /*   */ unsigned char *dgst_file (char *oid, char* fcont, int *len_h) { gcry_md_hd_t hd; gcry_error_t err; int algo; FILE *fp; unsigned char buf[1024]; size_t size; int i; unsigned char *h; unsigned char *ret_h; algo = gcry_md_map_name (oid); if (algo == GCRY_MD_NONE) return NULL; err = gcry_md_open(&hd, algo, 0); if (err) return NULL; fp = fopen (fcont, "r"); if (fp == NULL) return NULL; while (!feof (fp)) { size = fread (buf, 1, sizeof(buf), fp); gcry_md_write (hd, buf, size); } h = gcry_md_read(hd, 0); *len_h = gcry_md_get_algo_dlen (algo); ret_h = malloc(*len_h); memcpy(ret_h, h, *len_h); gcry_md_reset(hd); gcry_md_close(hd); return ret_h; } gcry_error_t one_file (const char *fname, char *fcontent, char *fcert) { gcry_error_t err; FILE *fp; ksba_reader_t r; ksba_writer_t w; ksba_cms_t cms; int i; const char *algoid; ksba_stop_reason_t stopreason; const char *s = NULL; size_t n; ksba_sexp_t p; char *dn; int idx; ksba_cert_t cert; int ii; unsigned char *cert_der; int cert_der_len; int f_der; int rez; ksba_sexp_t p1; size_t n1; gcry_sexp_t s_sig, s_hash, s_pkey, s_num; int gost_key; gcry_md_hd_t md; int rc; int digestlen; unsigned char *digest; gcry_md_hd_t data_md = NULL; ksba_isotime_t sigtime; unsigned char *sub_dn; //dn -  char *is_dn; //dn -   ksba_sexp_t sub_p; //  fprintf (stderr, "\n*** checking `%s' ***\n", fname); fp = fopen (fname, "r"); if (!fp) { fprintf (stderr, "can't open `%s'\n", fname); exit (1); } err = ksba_reader_new (&r); if (err) { fprintf (stderr, "can't reader `%s'\n", fname); exit (1); } err = ksba_reader_set_file (r, fp); if (err) { fprintf (stderr, "can't reader set `%s'\n", fname); exit (1); } /* Also create a writer so that cms.c won't return an error when writing processed content. */ err = ksba_writer_new (&w); if (err) { exit (1); } err = ksba_writer_set_cb (w, dummy_writer_cb, NULL); if (err) { exit (1); } switch (ksba_cms_identify (r)) { case KSBA_CT_SIGNED_DATA: s = "signed data"; break; case KSBA_CT_DATA: s = "data"; case KSBA_CT_ENVELOPED_DATA: if (s == NULL) s = "enveloped data"; case KSBA_CT_DIGESTED_DATA: if (s == NULL) s = "digested data"; case KSBA_CT_ENCRYPTED_DATA: if (s == NULL) s = "encrypted data"; case KSBA_CT_AUTH_DATA: if (s == NULL) s = "auth data"; default: if (s == NULL) s = "unknown"; printf ("identified as: %s\n", s); exit(1); } err = ksba_cms_new (&cms); if (err) { exit(1); } err = ksba_cms_set_reader_writer (cms, r, w); if (err) { exit(1); } rc = gcry_md_open (&data_md, 0, 0); if (rc) { fprintf (stderr, "md_open failed: \n"); exit(1);; } err = ksba_cms_parse (cms, &stopreason); if (err) { fprintf (stderr, "ksba_cms_parse: cannot parse %s\n", fname); exit(1); } ksba_cms_set_hash_function (cms, dummy_hash_fnc, NULL); do { err = ksba_cms_parse (cms, &stopreason); if (err) { fprintf (stderr, "ksba_cms_parse: cannot parse %s\n", fname); exit(1); } } while (stopreason != KSBA_SR_READY); /*  PKCS7  */ cert_der_len = 0; for (ii=0; (cert=ksba_cms_get_cert (cms, ii)); ii++) { cert_der = (unsigned char*)ksba_cert_get_image(cert, (size_t *)&cert_der_len); f_der = open(fcert, O_RDWR|O_TRUNC|O_CREAT, 0666); if (f_der == -1) { fprintf(stderr, "Bad open file=%s for cert\n", cert_der_len, fcert); exit(1); } /*    */ rez = write(f_der, cert_der, cert_der_len); close(f_der); /*      */ p1 = ksba_cert_get_public_key (cert); n1 = gcry_sexp_canon_len (p1, 0, NULL, NULL); if (!n1) { fprintf(stderr, "libksba did not return a proper S-Exp\n"); exit(1); } err = gcry_sexp_sscan ( &s_pkey, NULL, p1, n1); ksba_free (p1); if (err) { fprintf(stderr, "gcry_sexp_scan failed: %s\n", "pubkey"); exit(1); } /*   DN  */ sub_dn = ksba_cert_get_subject (cert, 0); ksba_cert_release (cert); } for (idx=0; idx < 1; idx++) { int algo; int info_pkalgo; unsigned char *s; int s_len; int len_h; unsigned char *dgst_h; /*  /PKCS#7 DN    is_dn      sub_p*/ /*       */ /*     ,       PKCS#7*/ err = ksba_cms_get_issuer_serial (cms, idx, &is_dn, &sub_p); if (err) { fprintf (stderr, "ksba_cms_get_issuer_serial cannot %s\n", fname); exit(1); } /*  */ algoid = ksba_cms_get_digest_algo (cms, idx); err = ksba_cms_get_sigattr_oids (cms, 0, "1.2.840.113549.1.7.1",&dn); if (err && err != -1) { fprintf (stderr, "ksba_cms_get_sigattr_oids cannot %s err=%d\n", fname, err); exit(1); } algo = gcry_md_map_name (algoid); /*   - (1)  */ gost_key = !memcmp(algoid, "1.2.643", 7); gcry_md_enable (data_md, algo); rc = gcry_md_open (&md, algo, 0); if (rc) { fprintf(stderr, "md_open failed:\n"); exit(1); } /* -*/ ksba_cms_set_hash_function (cms, HASH_FNC, data_md); /*    */ rc = ksba_cms_hash_signed_attrs (cms, idx); if (rc) { fprintf(stderr, "hashing signed attrs failed: \n"); gcry_md_close (md); continue; } gcry_md_final (md); digestlen = gcry_md_get_algo_dlen (algo); /*  */ digest = gcry_md_read (data_md, algo); gcry_md_close (md); if (gost_key){ /*   */ unsigned char *h; unsigned char c; int len_xy; /*   littlt-endian  big-endian*/ unsigned short arch = 1; /* 0x0001 */ h = digest; len_xy = *((unsigned char *) &arch) == 0 ? 0:gcry_md_get_algo_dlen (algo); /* */ for (i = 0; i < (len_xy/2); i++) { c = *(h + i); *(h + i) = *(h + len_xy - i - 1); *(h + len_xy - i - 1) = c; } } switch (gost_key) { case 0: if ( gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))", algoid, (int)digestlen, digest) ) { fprintf(stderr, "BUG\n"); exit (1); } break; case 1: /* ,  S-   */ if ( gcry_sexp_build (&s_hash, NULL, "(data(flags gost)(value %b))", (int)digestlen, digest) ) { exit (1); } break; default: exit (1); } /*   */ rc = ksba_cms_get_signing_time (cms, idx, sigtime); if (rc) { fprintf(stderr, "error getting signing time\n"); // *sigtime = 0; /* (we can't encode an error in the time string.) */ exit(1); } /*       PKCS#7 */ err = ksba_cms_get_message_digest (cms, idx, &dn, &n); if (err) { fprintf (stderr, "ksba_cms_get_message_digest cannot %s\n", fname); exit(1); } /*     */ dgst_h = dgst_file ((char *)algoid, (char *)fcontent, &len_h); if (dgst_h == NULL) { fprintf(stderr, "\nBad digest %s\n", fcontent); exit (1); } if (memcmp(dgst_h, dn, n)) { /* :  ,     ,    ..*/ fprintf(stderr, "\nBad content %s\n", fcontent); exit (1); } ksba_free (dn); putchar ('\n'); dn = ksba_cms_get_sig_val (cms, idx); if (!dn) { printf ("signer %d - signature not found\n", idx); exit(1); } n = gcry_sexp_canon_len ((ksba_sexp_t)dn, 0, NULL, NULL); if (!n){ fprintf(stderr, "libksba did not return a proper S-Exp\n"); exit(1); } err = gcry_sexp_sscan ( &s_sig, NULL, dn, n); if (err){ fprintf(stderr, "gcry_sexp_scan failed: %s\n", "Beda"); exit(1); } ksba_free (dn); } fprintf(stderr, "\n===========================================================\n"); if (*sigtime){ fprintf (stderr, "  :\n"); dump_isotime (sigtime); fprintf (stderr, "\n"); } else fprintf (stderr, "[date not given]\n"); fprintf(stderr, "\n : %s\n", sub_dn); fprintf(stderr, "\n : %s\n", is_dn); n = gcry_sexp_canon_len ((ksba_sexp_t)sub_p, 0, NULL, NULL); if (!n){ fprintf(stderr, "libksba did not return a proper S-Exp NUM\n"); exit(1); } err = gcry_sexp_sscan ( &s_num, NULL, sub_p, n); show_sexp ("\n :\n", s_num); fprintf(stderr, "\n===========================================================\n"); /* */ err = gcry_pk_verify (s_sig, s_hash, s_pkey); // if(err) { show_sexp ("s_pkey:\n", s_pkey); show_sexp ("s_sig:\n", s_sig); show_sexp ("s_hash:\n", s_hash); // } ksba_cms_release (cms); ksba_reader_release (r); fclose (fp); return (err); } int main (int argc, char **argv) { gcry_error_t err; unsigned char *h; int *len_h; if(argc != 4) { fprintf(stderr, "Usage: check_cms < > < > <   >\n"); exit(1); } err = one_file (argv[1], argv[2], argv[3]); if (err) { fprintf(stderr, "check_cms: verify %s error\n", argv[1]); } else { fprintf(stderr, "check_cms: verify %s Ok\n", argv[1]); fprintf(stderr, "check_cms:     %s\n", argv[3]); } exit (0); } 


لتبسيط المثال ، يتم كتابته على افتراض أن المستند له توقيع واحد فقط (توقيع واحد) ويتم تخزين شهادته في التوقيع. نقوم بحفظ الأداة check_cms_signed.c وترجمتها وتشغيلها:

 bash-4.3$ cc -o check_cms_signed check_cms_signed.c -lgcrypt libksba.so.8.11.6 bash-4.3$ ./check_cms_signed Usage: check_cms < > < > <    > bash-4.3$ 

والآن نتحقق من كيفية عمل الأداة:

 bash-4.3$ ./check_cms_signed test_cms_ksba.txt.p7s test_cms_ksba.txt save_cert.der *** checking `test_cms_ksba.txt.p7s' *** ===========================================================   : 2018-06-25 15:57:12  : SNILS=22222222222,INN=123456789012,O=CMS,STREET=PKCS7,L= ,ST=50  ,C=RU,GN=KSBA,SN=GCrypt,CN= GCrypt and KSBA,E=test@test.ru  : E=info@lissi.ru,CN= ,OU= 2,O= ,C=RU,ST= ,L=. ,STREET=.  .4 .7,OGRN=1234567890123,INN=123456789012  : (#73102E931BF9EA1369BA#) =========================================================== s_pkey: (public-key (ecc (curve "1.2.643.7.1.2.1.2.2") (hash "1.2.643.7.1.1.2.3") (q #044840A283684ECB537989536B9F080F7B914F3E6C153BC23F8A9212E303BF5B13905D29D0689CA5F2D0715D13FDC0FD387650193A7B46BE20C266776FAE36483750FE52A4C4E35EFB37EA64B48CB50ED5151289F59793574BD5FA59A2048A97FD94A1E5BB8DBF616B776D70C25774C1AC11CD6B6791D15850C37F7F176F49DBB6#) ) ) s_sig: (sig-val (gost (r #430C6EE1C0126F217B58EF5FB2E25055B2DF64AF0A1D769F2E7402145322ACD77B7D537B985AD7F3E3EDE94F9521D2F1E039B6F818B88D1CD709BE7BA97FE5E7#) (s #6A75146760E21BF6FA4CEDB41D37D938D5988DE048F9171796E764EC0E90891A7E02CA7F855C2468E11D217DB5C28DFAB1E31FF45793029FCDD666BE589F646A#) ) (hash stribog512) ) s_hash: (data (flags gost) (value #AD66AC68C832442C9520718AF9F67A87518CFE23098886C075F09DD19AC626DA65D7E39F6E0F81F5CF19C7DC5C3C9CC75FAD26A6C450ADD4C02FD31B49BA7CF1#) ) check_cms: verify test_cms_ksba.txt.p7s Ok check_cms:     save_cert.der bash-4.3$ 

إذا قمنا باستبدال / تغيير المستند المراد توقيعه ، فإننا نحصل على:

 bash-4.3$ ./check_cms_signed test_cms_ksba.txt.p7s test_cms_ksba_Change.txt save_cert.der *** checking `test_cms_ksba.txt.p7s' *** Bad content test_cms_ksba_Change.txt bash-4.3$ 

بعد التحقق بنجاح ، سيتم حفظ شهادة المُوقِّع في <مكان حفظ شهادة المُوقِّع
> (في المثال ، هذا هو ملف sace_cert.der).

لم تكن النتيجة أداة سيئة على الإطلاق ، والتي يمكن استخدامها عمليًا ولأغراض تعليمية.

ولكن تم تغطية ربع مسار الهدف النهائي فقط. خارج محادثتنا ، العمل مع المستندات المشفرة (PKCS # 7 ، VKO ، KEK) ، التوقيع على المستندات ، إنشاء طلبات الشهادة باقية. يستمر العمل.

Source: https://habr.com/ru/post/ar415611/


All Articles