
يقترب النصف الثاني من عام 2018 ، ومن المقرر أن يأتي
"عام 2000" في
البنية التحتية للمفاتيح العمومية على أساس التشفير الروسي. هذا يرجع إلى حقيقة ذلك
لا يُسمح باستخدام نظام توقيع GOST R 34.10-2001 لإنشاء توقيع بعد 31 ديسمبر 2018!
اليوم لا معنى لاستلام الشهادات بتوقيع وفقًا لـ GOST R 34.10-2001.
في الوقت نفسه ، تم تطوير الكثير من الخدمات أو التطبيقات على أساس OpenSSL ، والتي دعمت العمل مع GOST R 34.10-2001.
ولكن اليوم في الإصدار القياسي من opensl لا يوجد دعم لكل من GOST R 34.11-2012 و GOST R 34.10-2012. علاوة على ذلك ، في الإصدار 1.1 ، يتم
استبعاد دعم تشفير GOST من التوزيع القياسي ("كان محرك GOST قديمًا وبالتالي تمت إزالته.").
كل هذا يجعلنا نبحث عن طرق بديلة للعمل مع الشهادات ، مع التوقيع الإلكتروني ("رسائل تنسيق CMS") وكائنات PKI الأخرى القائمة على التشفير الروسي الجديد.
إحدى هذه الطرق الممكنة هي استخدام مكتبة
GCrypt . تدعم هذه المكتبة الخوارزميات الجديدة GOST R 34.11-2012 (خوارزميات التجزئة) و GOST R 34.10-2012 (خوارزميات التوقيع).
جيل زوج المفاتيح
لذا ، نبدأ بتوليد زوج مفاتيح يحتوي على مفاتيح خاصة وعامة. في الوقت الحاضر ، في التشفير الروسي ، هناك ثلاثة أنواع من مفاتيح التوقيع مع OID-S المقابل
- GOST R 34.10-2001 بطول مفتاح 256 بت ، OID 1.2.643.2.2.19 (0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x13) ؛
- GOST R 34.10-2012 بطول مفتاح 256 بت (فيما يلي GOST R 34.10-12-256) ، OID 1.2.643.7.1.1.1.1 (0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x01 ، 0x01 ، 0x01) ؛
- GOST R 34.10-2012 بطول مفتاح 512 بت (فيما يلي GOST R 34.10-12-512) ، OID 1.2.643.7.1.1.1.2 (0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x01 ، 0x01 ، 0x02).
ولاحظ على الفور أنه من حيث الرياضيات وخوارزميات التوليد وتنفيذها ، فإن مفاتيح GOST R 34.10-2001 و GOST R 34.10-12-256 متطابقة تمامًا! وكذلك الخوارزميات المتطابقة لتشكيل التوقيعات الالكترونية المبنية عليها. أي من هذه المفاتيح يمكن الحكم عليها فقط من خلال معلومات حول المفتاح الموجود ، على سبيل المثال ، في الشهادة. فلماذا احتاج الأمر إلى أودين مختلفين؟ التأكيد فقط على أنه عند إنشاء توقيع إلكتروني باستخدام مفتاح GOST R 34.10-2001 ، يجب استخدام التجزئة التي تم الحصول عليها وفقًا لـ GOST R 34.10-94 ، وعند استخدام مفتاح GOST R 34.10-12-256 ، يتم الحصول على التجزئة وفقًا لـ GOST R 34.10- 212 بطول 256 بت. على الرغم من ذلك ، وللتأكيد على ذلك ، هناك OID-S المقابلة:
- 1.2.643.2.2.3 (0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x03) - خوارزمية التوقيع GOST R 34.10-2001 مع المفتاح 256 مع التجزئة GOST R 34.11-94 ؛
- 1.2.643.7.1.1.3.2 (0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x01 ، 0x03 ، 0x02) - خوارزمية التوقيع GOST R 34.10-2012 مع المفتاح 256 مع التجزئة GOST R 34.11-2012 ؛
- 1.2.643.7.1.1.3.3 (0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x01 ، 0x03 ، 0x03) - خوارزمية التوقيع GOST R 34.10-2012 مع المفتاح 512 مع التجزئة GOST R 34.11-2012.
وبالتالي ، هناك بعض الفرز باستخدام OID-S ، ولكن هذا هو.
تنتمي مفاتيح عائلة GOST إلى العائلة الرئيسية على منحنيات بيضاوية الشكل. لإنشاء زوج مفاتيح ، تحتاج إلى تحديد نقطة أساسية على منحنى بيضاوي الشكل.
أوصت اللجنة الفنية لتوحيد معايير "أمن معلومات التشفير" (
TC 26 ) باستخدام نقطتي أساس للمفاتيح GOST R 34.10-2012-512:
- GOST2012-tc26-A (لقب في مصطلحات libgcrypt) مع OID 1.2.643.7.1.2.1.2.1 (0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x02 ، 0x01 ، 0x02 ، 0x01) ؛
- GOST2012-tc26-B مع OID 1.2.643.7.1.2.1.2.2 (0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x02 ، 0x01 ، 0x02 ، 0x02) ؛
بالنسبة لمفاتيح GOST R 34.10 بطول 256 بت ، يوصى بثلاث نقاط أساسية:
- GOST2001-CryptoPro-A مع OID om 1.2.643.2.2.35.1 (0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x23 ، 0x01) ؛
- GOST2001-CryptoPro-B مع OID 1.2.643.2.2.35.2 (0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x23 ، 0x02) ؛
- GOST2001-CryptoPro-C مع OID 1.2.643.2.2.35.3 (0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x23 ، 0x03).
بالنسبة لمفاتيح GOST R 34.10 التي يبلغ طولها 256 بت ، يتم تحديد نوعين آخرين للنقاط الأساسية:
- GOST2001-CryptoPro-XchA مع OID 1.2.643.2.2.36.0 (0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x24 ، 0x00) ؛
- GOST2001-CryptoPro-XchB مع OID 1.2.643.2.2.36.1 (0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x24 ، 0x01).
ومع ذلك ، في الواقع ، تشير هذه الأويضات إلى النقاط الأساسية لـ GOST2001-CryptoPro-A مع OID 1.2.643.2.2.35.1 و GOST2001-CryptoPro-C مع OID 1.2.643.2.2.35.3 على التوالي.
ويجب أن يؤخذ هذا في الاعتبار عند معالجة النقاط الأساسية باستخدام OID-S.
لإنشاء زوج مفاتيح ، يتم استخدام وظيفة gcry_pk_genkey للنموذج التالي:
gcry_error_t gcry_pk_genkey (gcry sexp t *key_pair, gcry sexp t key_spec ).
يجب تعيين المعلمات في متغير parms لإنشاء زوج المفاتيح بتنسيق
تعبير S- (sexp) الداخلي. لإنشاء زوج مفاتيح وفقًا لـ GOST ، يتم تعيين المعلمات في شكل تعبير S التالي:
(genkey ( (curve _))),
يحدد
ecc توليد زوج المفاتيح على المنحنيات الإهليلجية ، ويجب أن تشير نقطة الأساس إلى النقطة المحددة التي أوصى بها TK-26. إنها نقطة الأساس المحددة التي تحدد زوج المفاتيح الذي سيتم إنشاؤه. إذا حددت ، على سبيل المثال ، GOST2012-tc26-A أو GOST2012-tc26-B ، فسيتم إنشاء زوج مفاتيح وفقًا لـ GOST R 34.10-2012 بطول مفتاح 512 بت. بدلاً من لقب نقطة الأساس ، يمكنك تحديد OID مباشرة:
(genkey ( (curve «1.2.643.2.2.35.3»)))
في الحالة الأخيرة ، من المفترض أن يتم إنشاء زوج المفاتيح وفقًا لـ GOST R 34.10 بطول مفتاح 256 بت ونقطة أساس GOST2001-CryptoPro-C.
فيما يلي مثال على برنامج C يوضح إنشاء المفتاح
GenKey.c #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <gcrypt.h> /* 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); } int main(int argc, char* argv[]) { gpg_error_t err; gcry_sexp_t key_spec, key_pair, pub_key, sec_key; /* */ char *curve_gost[] = {"GOST2001-CryptoPro-A", "GOST2001-CryptoPro-B", "GOST2001-CryptoPro-C", "GOST2012-tc26-A", "GOST2012-tc26-B", NULL}; /* */ err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecc (curve %s)))", curve_gost[1]); if (err) { fprintf(stderr, "creating S-expression failed: %s\n", gcry_strerror (err)); exit (1); } err = gcry_pk_genkey (&key_pair, key_spec); if (err){ fprintf(stderr, "creating %s key failed: %s\n", argv[1], gcry_strerror (err)); exit(1); } /* S- */ show_sexp ("ECC GOST key pair:\n", key_pair); /* */ pub_key = gcry_sexp_find_token (key_pair, "public-key", 0); if (! pub_key) { fprintf(stderr, "public part missing in key\n"); exit(1); } /* S- */ show_sexp ("ECC GOST public key:\n", pub_key); /* */ sec_key = gcry_sexp_find_token (key_pair, "private-key", 0); if (! sec_key){ fprintf(stderr, "private part missing in key\n"); exit(1); } /* S- */ show_sexp ("ECC GOST private key:\n", sec_key); /* , */ gcry_sexp_release (key_pair); /* , */ gcry_sexp_release (key_spec); }
لبث المثال ، تحتاج إلى تشغيل الأمر:
$cc –o GenKey GenKey.c –lgcrypt $
بعد بدء تشغيل وحدة GenKey ، نحصل على
زوج المفاتيح ECC GOST key pair: (key-data (public-key (ecc (curve GOST2001-CryptoPro-B) (q
الآن ، بعد وجود المفتاح الخاص في متناول اليد ، يمكنك إنشاء توقيع إلكتروني.
تجزئة الوثيقة
يبدأ إنشاء توقيع إلكتروني (ES) لمستند بالحصول على قيمة تجزئة من المستند الذي يتم التوقيع عليه. للتوقيع على مستند ، يمكن تحديد أحد الخوارزميات:
- 1.2.643.2.2.3 (0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x03) - خوارزمية التوقيع GOST R 34.10-2001 مع المفتاح 256 مع التجزئة وفقًا لـ GOST R 34.11-94 مع طول التجزئة 256 بت ؛
- 1.2.643.7.1.1.3.2 (0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x01 ، 0x03 ، 0x02) - خوارزمية التوقيع GOST R 34.10-2012 بمفتاح 256 مع التجزئة وفقًا لـ GOST R 34.11-2012 بطول تجزئة 256 بت ؛
- 1.2.643.7.1.1.3.3 (0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x01 ، 0x03 ، 0x03) - خوارزمية التوقيع GOST R 34.10-2012 بمفتاح 512 مع التجزئة وفقًا لـ GOST R 34.11-2012 بطول تجزئة 512 بت.
لا تحدد هذه الخوارزميات نوع المفتاح الخاص الذي سيتم استخدامه للحصول على التوقيع الإلكتروني فحسب ، بل تحدد أيضًا خوارزمية دالة التجزئة. تطبق مكتبة GCrypt جميع أنواع الوظائف الثلاثة. خوارزمية التجزئة GOST R 34.11-94 (مع المعلمة OID 1.2.643.2.2.30.1 - 0x2a ، 0x85 ، 0x03 ، 0x02 ، 0x02 ، 0x1e ، 0x01) يتم تنفيذها تحت اللقب GOSTR3411_CP ، خوارزمية GOST R 34.11-2012 مع الطول يتم تنفيذ 256 بت (OID 1.2.43.7.1.1.2.2 - 0x2a و 0x85 و 0x03 و 0x07 و 0x01 و 0x01 و 0x02 و 0x02) تحت خوارزمية STRIBOG256 و GOST R 34.11-2012 بطول 512 بت (OID 1.2.43.7 .1.1.2.3 - 0x2a ، 0x85 ، 0x03 ، 0x07 ، 0x01 ، 0x01 ، 0x02 ، 0x03) يتم تنفيذها تحت اللقب STRIBOG512.
يوجد أدناه رمز الوحدة النمطية C لحساب قيمة التجزئة من مستند مخزن في ملف
digest_gcrypt.c: #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <gcrypt.h> int main(int argc, char* argv[]) { gpg_error_t err; int algo = GCRY_MD_NONE; int i; unsigned char *h; size_t size; gcry_md_hd_t hd; FILE *fp; unsigned char buf[1024]; char *dgst_gost[] = {"GOSTR3411_CP", "STRIBOG256", "STRIBOG512", NULL}; i = 0; /* -*/ if (argc == 3) algo = gcry_md_map_name (argv[1]); if (algo == GCRY_MD_NONE) { fprintf(stderr, "Usage: digest_gcrypt <nick_name_digest> <file_for_digest>\n"); fprintf(stderr, "<nick_name_digest>="); while (dgst_gost[i] != NULL){ if (i > 0 ) fprintf(stderr, " | ", dgst_gost[i]); fprintf(stderr, "%s", dgst_gost[i]); i++; } fprintf(stderr, "\n"); exit (1); } /* */ err = gcry_md_open(&hd, algo, 0); if (err) { fprintf (stderr, "LibGCrypt error %s\n", gcry_strerror (err)); exit (1); } /* */ if (!strcmp (argv[2], "-")) fp = stdin; else fp = fopen (argv[2], "r"); if (fp == NULL) { fprintf(stderr, "Cannot fopen file=%s\n", argv[2]); exit(1); } /* */ while (!feof (fp)) { size = fread (buf, 1, sizeof(buf), fp); gcry_md_write (hd, buf, size); } /* */ h = gcry_md_read(hd, 0); /* */ printf(" %s = %d ( )\n", argv[1], gcry_md_get_algo_dlen (algo)); printf(" %s:\n", argv[2]); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02x", h[i]); printf("\n"); fflush(stdout); /* */ gcry_md_reset(hd); gcry_md_close(hd); }
نترجم هذه الوحدة ونحصل على أداة حساب التجزئة:
$cc -o digest_file digest_file.c -lgcrypt $./digest_file Usage: digest_gcrypt <nick_name_digest> <file_for_digest> <nick_name_digest>=GOSTR3411_CP | STRIBOG256 | STRIBOG512 $./digest_file STRIBOG256 digest_file.c STRIBOG256 = 32 ( ) digest_file.c: f6818dfb26073747266dc721c332d703eb21f2b17e3433c809e0e23b68443d4a $
تكوين التوقيع الالكتروني والتحقق منه
الآن بعد أن حصلنا على المفتاح الخاص وتجزئة المستند ، يمكننا أيضًا إنشاء توقيع إلكتروني للمستند:
gcry_error_t gcry_pk_sign (gcry sexp t *r_sig, gcry sexp t data, gcry sexp t skey ),
r_sig -sexp-variable الذي سيتم فيه حفظ التوقيع الإلكتروني ،
skey - متغير
sexp بمفتاح خاص (انظر أعلاه) ، والذي يستخدم لإنشاء توقيع ،
data - sexp-variable ، الذي يشير إلى نوع التوقيع (في حالتنا ، gost) وتجزئة المستند الموقع.
يجب أن نتذكر أن قيمة التجزئة التي تم توفيرها لمدخل gcry_pk_sign لتوليد توقيع GOST R 34.10 يجب أن تكون بتنسيق نهاية كبيرة ، أي في الواقع مقلوب رأساً على عقب (كما قال أحد الأصدقاء: "التقليد الروسي في معالجة بايتات الهضم بالترتيب الصغير"). مع أخذ ذلك في الاعتبار ، فإن إعداد متغير الجنس datap هو كما يلي:
... gcry_sexp_t data; unsigned char c; int len_xy; gcry_mpi_t x; … printf("%s\n", *((unsigned char *) &arch) == 0 ? " big-endian" : " little-endian"); 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; } fprintf(stderr, " =%d\n", gcry_md_get_algo_dlen (algo)); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02X", h[i]); fflush(stdout); x = gcry_mpi_set_opaque_copy(NULL, h, gcry_md_get_algo_dlen (algo) * 8); err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); show_sexp ("data :\n", data);
كل شيء جاهز لاستلام التوقيع وعرضه <source: lang = "cpp"> ...
gcry_sexp_t sig_r، sig_s ؛
...
/ * توقيع التجزئة * /
err = gcry_pk_sign (& sig، data، sec_key)؛
if (err) {
fprintf (stderr، "فشل التوقيع:٪ s \ n"، gcry_strerror (err))؛
مخرج (1) ؛
}}
/ * نطبع التوقيع * /
show_sexp ("ECC GOST SIG: \ n"، sig) ؛
/ * تحديد وطباعة مكونات التوقيع r و s * /
sig_r = gcry_sexp_find_token (sig، "r"، 0) ؛
if (! sig_r) {
fprintf (stderr، "r part مفقود في sig \ n")؛
مخرج (1) ؛
}}
show_sexp ("ECC GOST Sig R-part: \ n"، sig_r)؛
sig_s = gcry_sexp_find_token (sig، "s"، 0) ؛
if (! sig_s) {
fprintf (stderr ، "جزء مفقود في sig \ n") ؛
مخرج (1) ؛
}}
show_sexp ("ECC GOST Sig S-part: \ n"، sig_s) ؛
... يمكنك التحقق من التوقيع على النحو التالي:
… err = gcry_pk_verify (sig, data, pub_key); if (err) { putchar ('\n'); show_sexp ("seckey:\n", sec_key); show_sexp ("data:\n", data); show_sexp ("sig:\n", sig); fprintf(stderr, "verify failed: %s\n", gcry_strerror (err)); exit(1); } …
التحقق من التوقيع الإلكتروني لـ GOST R 34.10 في الشهادات
أحد أهم عناصر البنية التحتية للمفتاح العام (PKI) هي شهادات X509. توصيات TC-26 بشأن تكوين وهيكل الشهادات مبينة في الوثيقة "المواصفات الفنية لاستخدام GOST R 34.10 ، GOST R 34.11 الخوارزميات في ملف تعريف الشهادة CRL (CRL) للبنية المفتوحة للمفتاح 9 من X. لجنة X. حماية المعلومات "(المحضر رقم 13 بتاريخ 04.24.2014)." ووفقًا لهذه التوصيات ، يصدر جميع المراجع المعتمدة في وزارة الاتصالات الروسية شهادات.
للتحقق من التوقيع في الشهادة ، من الضروري (انظر أعلاه) الحصول على تجزئة الشهادة التي تم التحقق منها وتوقيعها والمفتاح العام للشهادة الجذر. فقط لاحظ أنه بالنسبة لشهادة موقعة ذاتيًا ، يتم تخزين كل هذه البيانات في شهادة واحدة.
للعمل مع كائنات PKI / PKI (الشهادات و CMS والطلبات

وما إلى ذلك) ، كقاعدة ، يتم استخدام مكتبة KSBA ، والتي لا تدعم في الوقت الحالي توصيات TC-26 ، على الرغم من وجود
خبرة في هذا الدعم. في الأساس ، لا يوجد شيء يمنع إضافة الدعم لتوصيات TK-26 لمشروع ksba.
في هذه المرحلة ، في مرحلة اختبار GCrypt ، من المناسب استخدام لغات البرمجة النصية مثل
Python و Tcl وما إلى ذلك للعمل مع كائنات PKI / PKI (الشهادات وما إلى ذلك) مع التشفير الروسي. تم اختيار لغة البرمجة النصية
Tcl . من السهل والبسيط كتابة برنامج نموذجي عليه ، والذي يمكن بعد ذلك نقله إلى لغة C. يتضمن Tcl حزمة PKI التي تحتوي على إجراءات تحليل كائنات PKI ، على وجه الخصوص ، إجراء تحليل الشهادات :: pki :: x509 :: parse_cert. بناءً على إجراء parse_cert ، تم تطوير إجراء parse_gost_cert ، الموجود في الملف
parse_cert_gost_oid.tcl proc parse_cert_gost {cert} { # parray ::pki::oids #puts "parse_cert_gost=$cert" set cert_seq "" if { [string range $cert 0 9 ] == "-----BEGIN" } { array set parsed_cert [::pki::_parse_pem $cert "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"] set cert_seq $parsed_cert(data) } else { #FORMAT DER set cert_seq $cert } set finger [::sha1::sha1 $cert_seq] set ret(fingerprint) $finger binary scan $cert_seq H* certdb set ret(certdb) $certdb #puts "CERTDB=$certdb" array set ret [list] # Decode X.509 certificate, which is an ASN.1 sequence ::asn::asnGetSequence cert_seq wholething ::asn::asnGetSequence wholething cert set ret(cert) $cert set ret(cert) [::asn::asnSequence $ret(cert)] if {0} { set ff [open "/tmp/tbs.der" w] fconfigure $ff -translation binary puts -nonewline $ff $ret(cert) close $ff } binary scan $ret(cert) H* ret(cert) ::asn::asnPeekByte cert peek_tag if {$peek_tag != 0x02} { # Version number is optional, if missing assumed to be value of 0 ::asn::asnGetContext cert - asn_version ::asn::asnGetInteger asn_version ret(version) incr ret(version) } else { set ret(version) 1 } ::asn::asnGetBigInteger cert ret(serial_number) ::asn::asnGetSequence cert data_signature_algo_seq ::asn::asnGetObjectIdentifier data_signature_algo_seq ret(data_signature_algo) ::asn::asnGetSequence cert issuer ::asn::asnGetSequence cert validity ::asn::asnGetUTCTime validity ret(notBefore) ::asn::asnGetUTCTime validity ret(notAfter) ::asn::asnGetSequence cert subject ::asn::asnGetSequence cert pubkeyinfo binary scan $pubkeyinfo H* pubkeyinfoG set ret(pubkeyinfo) $pubkeyinfoG ::asn::asnGetSequence pubkeyinfo pubkey_algoid binary scan $pubkey_algoid H* pubkey_algoidG set ret(pubkey_algoid) $pubkey_algoidG ::asn::asnGetObjectIdentifier pubkey_algoid ret(pubkey_algo) ::asn::asnGetBitString pubkeyinfo pubkey set extensions_list [list] while {$cert != ""} { ::asn::asnPeekByte cert peek_tag switch -- [format {0x%02x} $peek_tag] { "0xa1" { ::asn::asnGetContext cert - issuerUniqID } "0xa2" { ::asn::asnGetContext cert - subjectUniqID } "0xa3" { ::asn::asnGetContext cert - extensions_ctx ::asn::asnGetSequence extensions_ctx extensions while {$extensions != ""} { ::asn::asnGetSequence extensions extension ::asn::asnGetObjectIdentifier extension ext_oid ::asn::asnPeekByte extension peek_tag if {$peek_tag == 0x1} { ::asn::asnGetBoolean extension ext_critical } else { set ext_critical false } ::asn::asnGetOctetString extension ext_value_seq set ext_oid [::pki::_oid_number_to_name $ext_oid] set ext_value [list $ext_critical] switch -- $ext_oid { id-ce-basicConstraints { ::asn::asnGetSequence ext_value_seq ext_value_bin if {$ext_value_bin != ""} { ::asn::asnGetBoolean ext_value_bin allowCA } else { set allowCA "false" } if {$ext_value_bin != ""} { ::asn::asnGetInteger ext_value_bin caDepth } else { set caDepth -1 } lappend ext_value $allowCA $caDepth } default { binary scan $ext_value_seq H* ext_value_seq_hex lappend ext_value $ext_value_seq_hex } } lappend extensions_list $ext_oid $ext_value } } } } set ret(extensions) $extensions_list ::asn::asnGetSequence wholething signature_algo_seq ::asn::asnGetObjectIdentifier signature_algo_seq ret(signature_algo) ::asn::asnGetBitString wholething ret(signature) # Convert values from ASN.1 decoder to usable values if needed set ret(notBefore) [::pki::x509::_utctime_to_native $ret(notBefore)] set ret(notAfter) [::pki::x509::_utctime_to_native $ret(notAfter)] set ret(serial_number) [::math::bignum::tostr $ret(serial_number)] set ret(data_signature_algo) [::pki::_oid_number_to_name $ret(data_signature_algo)] set ret(signature_algo) [::pki::_oid_number_to_name $ret(signature_algo)] set ret(pubkey_algo) [::pki::_oid_number_to_name $ret(pubkey_algo)] set ret(issuer) [::pki::x509::_dn_to_string $issuer] set ret(subject) [::pki::x509::_dn_to_string $subject] set ret(signature) [binary format B* $ret(signature)] binary scan $ret(signature) H* ret(signature) # Handle RSA public keys by extracting N and E #puts "PUBKEY_ALGO=$ret(pubkey_algo)" switch -- $ret(pubkey_algo) { "rsaEncryption" { set pubkey [binary format B* $pubkey] binary scan $pubkey H* ret(pubkey) ::asn::asnGetSequence pubkey pubkey_parts ::asn::asnGetBigInteger pubkey_parts ret(n) ::asn::asnGetBigInteger pubkey_parts ret(e) set ret(n) [::math::bignum::tostr $ret(n)] set ret(e) [::math::bignum::tostr $ret(e)] set ret(l) [expr {int([::pki::_bits $ret(n)] / 8.0000 + 0.5) * 8}] set ret(type) rsa } "GostR2012_256" - "GostR2012_512" - "GostR2001" - "1.2.643.2.2.19" - "1.2.643.7.1.1.1.1" - "1.2.643.7.1.1.1.2" { # gost2001, gost2012-256,gost2012-512 set pubkey [binary format B* $pubkey] #puts "LL=[string length $pubkey]" if {[string length $pubkey] < 100} { set pubk [string range $pubkey 2 end] } else { set pubk [string range $pubkey 3 end] } set pubkey_revert [string reverse $pubk] binary scan $pubkey_revert H* ret(pubkey_rev) binary scan $pubkey H* ret(pubkey) set ret(type) gost ::asn::asnGetSequence pubkey_algoid pubalgost #OID - ::asn::asnGetObjectIdentifier pubalgost ret(paramkey) set ret(paramkey) [::pki::_oid_number_to_name $ret(paramkey)] #OID - ::asn::asnGetObjectIdentifier pubalgost ret(hashkey) set ret(hashkey) [::pki::_oid_number_to_name $ret(hashkey)] #puts "ret(paramkey)=$ret(paramkey)\n" #puts "ret(hashkey)=$ret(hashkey)\n" } } return [array get ret] } proc set_nick_for_oid {} { # set ::pki::oids(1.2.643.2.2.19) "gost2001pubKey" # set ::pki::oids(1.2.643.2.2.3) "gost2001withGOST3411_94" set ::pki::oids(1.2.643.100.1) "OGRN" set ::pki::oids(1.2.643.100.5) "OGRNIP" set ::pki::oids(1.2.643.3.131.1.1) "INN" set ::pki::oids(1.2.643.100.3) "SNILS" # set ::pki::oids(1.2.643.2.2.3) " 34.10-2001-256" set ::pki::oids(1.2.643.7.1.1.3.2) " 34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) " 34.10-2012-512" # set ::pki::oids(1.2.643.2.2.3) "gost" # set ::pki::oids(1.2.643.7.1.1.3.2) "gost" # set ::pki::oids(1.2.643.7.1.1.3.3) "gost" # # set ::pki::oids(1.2.643.2.2.19) " 34.10-2001" # set ::pki::oids(1.2.643.7.1.1.1.1) " 34.10-2012 256 " # set ::pki::oids(1.2.643.7.1.1.1.2) " 34.10-2012 512 " set ::pki::oids(1.2.643.2.2.19) "GostR2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GostR2012_256" set ::pki::oids(1.2.643.7.1.1.1.2) "GostR2012_512" #Oid- 34.10-2001 34.10-2012-256 set ::pki::oids(1.2.643.2.2.35.0) "GOST2001-test" set ::pki::oids(1.2.643.2.2.35.1) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.35.2) "GOST2001-CryptoPro-B" set ::pki::oids(1.2.643.2.2.35.3) "GOST2001-CryptoPro-C" # { "GOST2001-CryptoPro-A", set ::pki::oids("GOST2001-CryptoPro-XchA" }, # { "GOST2001-CryptoPro-C", set ::pki::oids("GOST2001-CryptoPro-XchB" }, set ::pki::oids(1.2.643.2.2.36.0) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.36.1) "GOST2001-CryptoPro-C" #Oid- 34.10-2012-512 set ::pki::oids(1.2.643.7.1.2.1.2.1) "GOST2012-tc26-A" set ::pki::oids(1.2.643.7.1.2.1.2.2) "GOST2012-tc26-B" #Nick set ::pki::oids(1.2.643.7.1.1.2.2) "STRIBOG256" set ::pki::oids(1.2.643.7.1.1.2.3) "STRIBOG512" set ::pki::oids(1.2.643.2.2.30.1) "GOSTR3411_CP" }
تم تصميم إجراء parse_gost_cert لتحليل الشهادات القائمة على التشفير الروسي.
يحتوي هذا الملف أيضًا على إجراء تعيين الألقاب إلى oid-s من التشفير الروسي ، مع مراعاة مشروع GCrypt:
proc set_nick_for_oid {} { set ::pki::oids(1.2.643.100.1) "OGRN" set ::pki::oids(1.2.643.100.5) "OGRNIP" set ::pki::oids(1.2.643.3.131.1.1) "INN" set ::pki::oids(1.2.643.100.3) "SNILS" # set ::pki::oids(1.2.643.2.2.3) " 34.10-2001-256" set ::pki::oids(1.2.643.7.1.1.3.2) " 34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) " 34.10-2012-512" # set ::pki::oids(1.2.643.2.2.19) "GostR2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GostR2012_256" set ::pki::oids(1.2.643.7.1.1.1.2) "GostR2012_512" #Oid- 34.10-2001 34.10-2012-256 set ::pki::oids(1.2.643.2.2.35.0) "GOST2001-test" set ::pki::oids(1.2.643.2.2.35.1) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.35.2) "GOST2001-CryptoPro-B" set ::pki::oids(1.2.643.2.2.35.3) "GOST2001-CryptoPro-C" set ::pki::oids(1.2.643.2.2.36.0) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.36.1) "GOST2001-CryptoPro-C" #Oid- 34.10-2012-512 set ::pki::oids(1.2.643.7.1.2.1.2.1) "GOST2012-tc26-A" set ::pki::oids(1.2.643.7.1.2.1.2.2) "GOST2012-tc26-B" #Nick set ::pki::oids(1.2.643.7.1.1.2.2) "STRIBOG256" set ::pki::oids(1.2.643.7.1.1.2.3) "STRIBOG512" set ::pki::oids(1.2.643.2.2.30.1) "GOSTR3411_CP" }
يسمح لك إجراء parse_gost_cert بالحصول على
شهادة TBS وتوقيع الشهادة ونوع التوقيع والمفتاح العام. إذا كنا نفكر في شهادة موقعة ذاتيًا ، فهذا يكفي للتحقق من التوقيع. إذا تحققنا من توقيع شهادة موقعة (صادرة) من قبل شهادة أخرى (لا يتطابق المصدر وموضوع الشهادة) ، فإن إجراءات الحصول على معلومات للتحقق من التوقيع هي كما يلي:
- من الشهادة التي تم التحقق منها ، نستخرج شهادة TBS ونوع التوقيع والتوقيع نفسه ؛
- نستخرج المفتاح العمومي من الشهادة الجذرية.
المسؤول الأكبر في إعداد البيانات المصدر للتحقق من توقيع الشهادة هو الالتزام الصارم بتوصيات TK-26. للحصول على قيمة مفتاح عام ، تبدو كما يلي:
يتطابق تمثيل المفتاح العام لـ GostR3410-2012-256-PublicKey مع تمثيل المفتاح العام لـ GOST R 34.10-2001 [IETF RFC 4491] ، ويجب أن يحتوي على 64 ثمانًا ، حيث تحتوي أول 32 ثمانًا من الإحداثيات x في عرض النهاية الصغيرة والثاني 32 ثمان تحتوي على الإحداثيات ذ في وجهة النظر endian القليل.
يجب أن يحتوي GostR3410-2012-512-Public Key Public View View
128 ثماني بتات ، حيث تحتوي أول ثماني ثمانيات 64 على إحداثي س في العرض ذي الطرف الصغير ، وتحتوي الثماني عثمانية الثانية على إحداثي ص في العرض ذي النهاية الصغيرة.
عند تحميل التوقيع ، يجب أن يسترشد ما يلي:
تُستخدم خوارزمية توقيع GOST R 34.10-2012 ذات طول رمز تجزئة 256 بت لإنشاء توقيع رقمي في شكل رقمين 256 بت ، r و s. يتطابق تمثيلها في شكل سلسلة الثماني (OCTET STRING) مع تمثيل التوقيع GOST R 34.10-2001 [IETF RFC 4491] ويتكون من 64 ثمانية ؛ تحتوي أول ثماني وثلاثين رقمًا أولية على الرقم s في التمثيل ذي النهاية الكبيرة (تتم كتابة أعلى ثماني بتات أولاً) ، وتحتوي الثماني والثلاثون الثانية الثانية على الرقم r في التمثيل ذي النهاية الكبيرة.
يتم استخدام خوارزمية توقيع GOST R 34.10-2012 مع 512 رمز تجزئة لتوليد توقيع رقمي في شكل رقمين 512 بت ، مفاتيح عامة وفقًا لـ r و s. يتكون تمثيلها كسلسلة ثمانية (OCTET STRING) من 128 ثمانيًا ؛ تحتوي أول ثماني ثمانيات 64 على العدد s في التمثيل ذو النهاية الكبيرة (تتم كتابة أعلى ثماني بتات أولاً) ، وتحتوي الثماني 64 ثانية الثانية على الرقم r في التمثيل ذي النهاية الكبيرة.
بناءً على هذه التوصيات ، تعد وحدة Tcl
parse_certs_for_verify_load.tcl بيانات المصدر للتحقق من توقيع الشهادة
يبدو مثل هذا: #!/usr/bin/tclsh # PKI package require pki # - source parse_cert_gost_oid.tcl if {$argc != 2} { puts "Usage: parse_certs_for_verify_load.tcl < > < >" exit 1 } # if {[file exists "[lindex $argv 0]"] == 0 } { puts "Usage: parse_certs_for_verify_load.tcl < > < >" puts " [lindex $argv 0]" exit 1 } # if {[file exists "[lindex $argv 1]"] == 0 } { puts "Usage: parse_certs_for_verify_load.tcl < > < >" puts " [lindex $argv 1]" exit 1 } # nick- - oid- set_nick_for_oid set file [lindex $argv 0] set f [open $file r] set cert [read $f] close $f #READ DER-format if { [string range $cert 0 9 ] != "-----BEGIN" } { set fd [open $file] chan configure $fd -translation binary set cert [read $fd] close $fd } array set cert_user [parse_cert_gost $cert] # -26 set len_sign [expr [string length $cert_user(signature)] /2] set sign_r [string range $cert_user(signature) $len_sign end] set sign_s [string range $cert_user(signature) 0 [expr $len_sign - 1]] #puts " : $file" set file [lindex $argv 1] set f [open $file r] set cert [read $f] close $f #READ DER if { [string range $cert 0 9 ] != "-----BEGIN" } { set fd [open $file] chan configure $fd -translation binary set cert [read $fd] close $fd } # array set cert_ca [parse_cert_gost $cert] # -26 set len_key [expr [string length $cert_ca(pubkey_rev)]/2] set key_pub_left [string range $cert_ca(pubkey_rev) $len_key end] set key_pub_right [string range $cert_ca(pubkey_rev) 0 [expr $len_key - 1]] puts "/* C-: */" #TBS- puts "char tbc\[\] = \"[string toupper $cert_user(cert)]\";" # - puts "char hash_type\[\] = \"$cert_ca(hashkey)\";" # puts "unsigned char pub_key_ca\[\] = \"(public-key \"" puts "\"(ecc \"" puts "\" (curve $cert_ca(paramkey))\"" puts "\" (q #04[string toupper $key_pub_left$key_pub_right]#)\"" puts "\")\"" puts "\")\";" # puts "unsigned char sig_cert\[\] = \"(sig-val\"" puts "\"($cert_ca(type) \"" puts "\" (r #[string toupper $sign_r]#)\"" puts "\" (s #[string toupper $sign_s]#)\"" puts "\")\"" puts "\")\";" puts "/* TEST_from_TCL.h*/" puts "/* TEST_from_Tcl.c: cc -o TEST_from_Tcl TEST_from_Tcl.c -lgcrypt TEST_from_Tcl*/"
للاختبار ، نأخذ شهادتين حقيقيتين:شهادة \ "UTs 1 IS GUTs.pem \"-----BEGIN CERTIFICATE-----
MIIGrDCCBlugAwIBAgILAOvBBVQAAAAAAFkwCAYGKoUDAgIDMIIBSjEeMBwGCSqG
SIb3DQEJARYPZGl0QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJSVTEcMBoGA1UECAwT
Nzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMT8wPQYD
VQQJDDYxMjUzNzUg0LMuINCc0L7RgdC60LLQsCwg0YPQuy4g0KLQstC10YDRgdC6
0LDRjywg0LQuIDcxLDAqBgNVBAoMI9Cc0LjQvdC60L7QvNGB0LLRj9C30Ywg0KDQ
vtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDExGjAYBggqhQMDgQMB
ARIMMDA3NzEwNDc0Mzc1MUEwPwYDVQQDDDjQk9C+0LvQvtCy0L3QvtC5INGD0LTQ
vtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgDAeFw0xNjAzMTYxMjAy
NTFaFw0yNzA3MTIxMjAyNTFaMIIBITEaMBgGCCqFAwOBAwEBEgwwMDc3MTA0NzQz
NzUxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEeMBwGCSqGSIb3DQEJARYPZGl0
QG1pbnN2eWF6LnJ1MTwwOgYDVQQJDDMxMjUzNzUg0LMuINCc0L7RgdC60LLQsCDR
g9C7LiDQotCy0LXRgNGB0LrQsNGPINC0LjcxLDAqBgNVBAoMI9Cc0LjQvdC60L7Q
vNGB0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRUwEwYDVQQHDAzQnNC+0YHQutCy0LAx
HDAaBgNVBAgMEzc3INCzLiDQnNC+0YHQutCy0LAxCzAJBgNVBAYTAlJVMRswGQYD
VQQDDBLQo9CmIDEg0JjQoSDQk9Cj0KYwYzAcBgYqhQMCAhMwEgYHKoUDAgIjAQYH
KoUDAgIeAQNDAARAx70Y7WYQ4ODtdiSSx3MJnr1GQBEIExiPO/LWj1TRKES1OcDI
YgtdOBGVYSvbsStl10jkAOG0OpnGsd2by4m+LaOCA0MwggM/MA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFBGIaV7vyOlz23pXNbzSAfMF/qfRMAsGA1UdDwQEAwIB
hjCCAYsGA1UdIwSCAYIwggF+gBSLmDuJGFHo75wCeLjqyNQgslXJXaGCAVKkggFO
MIIBSjEeMBwGCSqGSIb3DQEJARYPZGl0QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJS
VTEcMBoGA1UECAwTNzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB
0LrQstCwMT8wPQYDVQQJDDYxMjUzNzUg0LMuINCc0L7RgdC60LLQsCwg0YPQuy4g
0KLQstC10YDRgdC60LDRjywg0LQuIDcxLDAqBgNVBAoMI9Cc0LjQvdC60L7QvNGB
0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDEx
GjAYBggqhQMDgQMBARIMMDA3NzEwNDc0Mzc1MUEwPwYDVQQDDDjQk9C+0LvQvtCy
0L3QvtC5INGD0LTQvtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgIIQ
NGgeQMtB7zOpoLfIdpKaKTBZBgNVHR8EUjBQMCagJKAihiBodHRwOi8vcm9zdGVs
ZWNvbS5ydS9jZHAvZ3VjLmNybDAmoCSgIoYgaHR0cDovL3JlZXN0ci1wa2kucnUv
Y2RwL2d1Yy5jcmwwJgYFKoUDZG8EHQwb0JrRgNC40L/RgtC+LdCf0YDQviBDU1Ag
My42MCUGA1UdIAQeMBwwCAYGKoUDZHEBMAgGBiqFA2RxAjAGBgRVHSAAMIHGBgUq
hQNkcASBvDCBuQwj0J/QkNCa0JwgwqvQmtGA0LjQv9GC0L7Qn9GA0L4gSFNNwrsM
INCf0JDQmiDCq9CT0L7Qu9C+0LLQvdC+0Lkg0KPQpsK7DDbQl9Cw0LrQu9GO0YfQ
tdC90LjQtSDihJYgMTQ5LzMvMi8yLTk5OSDQvtGCIDA1LjA3LjIwMTIMONCX0LDQ
utC70Y7Rh9C10L3QuNC1IOKEliAxNDkvNy8xLzQvMi02MDMg0L7RgiAwNi4wNy4y
MDEyMAgGBiqFAwICAwNBAKVYokUvb7XAMPJF38ZPKO2BFBldmGEfqsfmsiO35Y52
kTkx512H3YLqWMrOLjIfVMJhc+DTCNeXWY6bhK4/DRU=
-----END CERTIFICATE-----
وشهادة جذره \ "SEC Minkomsvyaz.pem \":-----BEGIN CERTIFICATE-----
MIIFGTCCBMigAwIBAgIQNGgeQMtB7zOpoLfIdpKaKTAIBgYqhQMCAgMwggFKMR4w
HAYJKoZIhvcNAQkBFg9kaXRAbWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYD
VQQIDBM3NyDQsy4g0JzQvtGB0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAx
PzA9BgNVBAkMNjEyNTM3NSDQsy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXR
gNGB0LrQsNGPLCDQtC4gNzEsMCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfR
jCDQoNC+0YHRgdC40LgxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqF
AwOBAwEBEgwwMDc3MTA0NzQzNzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg
0YPQtNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMB4XDTEyMDcy
MDEyMzExNFoXDTI3MDcxNzEyMzExNFowggFKMR4wHAYJKoZIhvcNAQkBFg9kaXRA
bWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYDVQQIDBM3NyDQsy4g0JzQvtGB
0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAxPzA9BgNVBAkMNjEyNTM3NSDQ
sy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXRgNGB0LrQsNGPLCDQtC4gNzEs
MCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfRjCDQoNC+0YHRgdC40LgxGDAW
BgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqFAwOBAwEBEgwwMDc3MTA0NzQz
NzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg0YPQtNC+0YHRgtC+0LLQtdGA
0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMGMwHAYGKoUDAgITMBIGByqFAwICIwEGByqF
AwICHgEDQwAEQI+lv3kQI8jWka1kMVdbvpvFioP0Pyn3Knmp+2XD6KgPWnXEIlSR
X8g/IYracDr51YsNc2KE3C7mkH6hA3M3ofujggGCMIIBfjCBxgYFKoUDZHAEgbww
gbkMI9Cf0JDQmtCcIMKr0JrRgNC40L/RgtC+0J/RgNC+IEhTTcK7DCDQn9CQ0Jog
wqvQk9C+0LvQvtCy0L3QvtC5INCj0KbCuww20JfQsNC60LvRjtGH0LXQvdC40LUg
4oSWIDE0OS8zLzIvMi05OTkg0L7RgiAwNS4wNy4yMDEyDDjQl9Cw0LrQu9GO0YfQ
tdC90LjQtSDihJYgMTQ5LzcvMS80LzItNjAzINC+0YIgMDYuMDcuMjAxMjAuBgUq
hQNkbwQlDCPQn9CQ0JrQnCDCq9Ca0YDQuNC/0YLQvtCf0YDQviBIU03CuzBDBgNV
HSAEPDA6MAgGBiqFA2RxATAIBgYqhQNkcQIwCAYGKoUDZHEDMAgGBiqFA2RxBDAI
BgYqhQNkcQUwBgYEVR0gADAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUi5g7iRhR6O+cAni46sjUILJVyV0wCAYGKoUDAgIDA0EA23Re
ec/Y27rpMi+iFbgWCazGY3skBTq5ZGsQKOUxCe4mO7UBDACiWqdA0nvqiQMXeHgq
o//fO9pxuIHtymwyMg==
-----END CERTIFICATE-----
سنقوم بإعداد البيانات الأولية للتحقق من الشهادة "UTs 1 IS GUTs.pem": $ ./parse_certs_for_verify_load.tcl " 1 .pem" " .pem" > TEST_from_TCL.h $echo " TEST_from_TCL.h" $cat TEST_from_TCL.h /* C-: */ char tbc[] = "3082065B . . . "; char hash_type[] = "GOSTR3411_CP"; unsigned char pub_key_ca[] = "(public-key " "(ecc " " (curve GOST2001-CryptoPro-A)" " (q #040FA8E8C365FBA9792AF7293FF4838AC59BBE5B573164AD91D6C8231079BFA58FFBA1377303A17E90E62EDC8462730D8BD5F93A70DA8A213FC85F915422C4755A#)" ")" ")"; unsigned char sig_cert[] = "(sig-val" "(gost " " (r #913931E75D87DD82EA58CACE2E321F54C26173E0D308D797598E9B84AE3F0D15#)" " (s #A558A2452F6FB5C030F245DFC64F28ED8114195D98611FAAC7E6B223B7E58E76#)" ")" ")"; /* TEST_from_TCL.h*/ /* TEST_from_Tcl.c: cc -o TEST_from_Tcl TEST_from_Tcl.c -lgcrypt TEST_from_Tcl*/ $
يتم تنفيذ التحقق من توقيع الشهادة من قبل الوحدة:TEST_from_TCL.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <gcrypt.h> #include "TEST_from_TCL.h" #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define xmalloc(a) gcry_xmalloc ((a)) 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); } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * hex2buffer (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) return NULL; /* Invalid hex digits. */ ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } int main(int argc, char* argv[]) { gpg_error_t err; int algo; gcry_md_hd_t hd; unsigned char *tbs_ptr; size_t len_tbs; int i; unsigned char *h; gcry_sexp_t pub_key; gcry_sexp_t data; gcry_sexp_t sig; gcry_mpi_t x; int len_xy; unsigned char c; /* little-endian big-endian*/ unsigned short arch = 1; /* 0x0001 */ tbs_ptr = hex2buffer(tbc, &len_tbs); if (tbs_ptr == NULL) { fprintf (stderr, "Bad tbs\n"); exit(1); } algo = gcry_md_map_name (hash_type); if (algo == GCRY_MD_NONE) { fprintf (stderr, "Unknown algorithm '%s'\n", hash_type); exit (1); } err = gcry_md_open(&hd, algo, 0); if (err) { fprintf (stderr, "LibGCrypt error %s/%s\n", gcry_strsource (err), gcry_strerror (err)); exit (1); } gcry_md_write (hd, tbs_ptr, len_tbs); h = gcry_md_read(hd, 0); // len_xy = gcry_md_get_algo_dlen (algo); /* */ printf("%s\n", *((unsigned char *) &arch) == 0 ? " big-endian" : " little-endian"); 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; } fprintf(stderr, " =%d\n", gcry_md_get_algo_dlen (algo)); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02X", h[i]); // printf("\n %s\n", tbc); fflush(stdout); /* */ x = gcry_mpi_set_opaque_copy(NULL, h, gcry_md_get_algo_dlen (algo) * 8); /* */ gcry_md_reset(hd); gcry_md_close(hd); /* */ err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); show_sexp ("ECC GOST data cert:\n", data); fprintf (stderr, "\nStep 1\n"); /* */ err = gcry_sexp_sscan (&pub_key, NULL, pub_key_ca, strlen (pub_key_ca)); if (err){ fprintf(stderr, "TEST_SEXP: er gcry_sexp_sscan for pub_key_ca\n"); exit(1); } show_sexp ("ECC GOST public key:\n", pub_key); fprintf (stderr, "Step 2\n"); /* */ err = gcry_sexp_sscan (&sig, NULL, sig_cert, strlen (sig_cert)); if (err){ fprintf(stderr, "TEST_SEXP: er gcry_sexp_sscan for sig_cert\n"); exit(1); } show_sexp ("ECC GOST sig cert:\n", sig); fprintf (stderr, "Step 3\n"); /* */ err = gcry_pk_verify (sig, data, pub_key); if (err) { fprintf (stderr, "TEST_SEXP: verify cert failed\n"); exit (1); } fprintf (stderr, "TEST_SEXP: verify cert OK!!\n"); }
نحن نترجم وننفذ أداة TEST_from_TCL: $cc –o TEST_from_TCL TEST_from_TCL.c –lgcrypt $./TEST_from_TCL little-endian =32 D485903E7E8D60820118329060C558B9C733D53CA608C0C79363ECE7B4C1F799ECC GOST data cert: (data (flags gost) (value
كما ترى ، نجح التحقق من توقيع الشهادة "UTs 1 IS GUTs.pem". يبقى للتحقق من شهادة الجذر نفسها "GUT Minkomsvyaz.pem." الأمر بسيط ، فقط قم بتشغيل الأمر: $ parse_certs_for_verify_load.tcl " .pem" " .pem" > TEST_from_TCL.h $ ..
إذا كان أي شخص يريد التحقق من الشهادات باستخدام مفاتيح GOST الأخرى (GOST R 34.10-2012-256 أو GOST R 34.10-2012-512) ، فيمكنه استخدام CAFL63 CA وإعداد أي شهادات:
لذا ، أظهرت الأبحاث المنجزة أن مكتبة GCrypt قد تكون جيدة تستخدم للعمل مع التشفير الروسي. وينظر إلى الآفاق المباشرة في إنهاء مكتبة KSBA وتوسيع حزمة pki للغة البرمجة النصية Tcl (أو ربما Python) مع دعم التشفير الروسي.أولئك الذين يرغبون في استخدام مكتبة GCrypt للتشفير ، أوصي بإلقاء نظرة هنا .