بسيط sprintf ASN1 الترميز

صورة يحدد بناء جملة ASN.1 طريقة فريدة لتحويل قيم متغيرات الأنواع الصالحة إلى تسلسل من البايتات للإرسال عبر شبكة. في ASN.1 ، يطلق عليه قواعد الترميز الأساسية (BER). القواعد تكرارية ، لذا فإن تشفير الكائنات المركبة عبارة عن تسلسل للتسلسلات المشفرة للكائنات المكونة. يصف بروتوكول ASN.1 بنية البيانات بلغة بسيطة ومفهومة .

تتكون كل قيمة مرسلة - كلا النوع الأساسي والمشتق - من ثلاثة حقول:

  • ID.
  • طول حقل البيانات (بالبايت) ؛
  • مجال البيانات.

إذا حددت دائمًا طول حقل البيانات (أعتقد أن هذه هي قاعدة النغمة الجيدة) ، فلن يتم استخدام علامة نهاية حقل البيانات.

هناك العديد من المجمعين المختلفين لـ ASN.1 ، المدفوعين والمجانيين ، بلغات البرمجة المختلفة ، لكننا نرغب في الحصول على شيء بسيط للغاية.

الغالبية العظمى من مطوري البرمجيات يجدون المجمع القياسي ASN.1 . اعتقدت ذلك أيضا حتى وقت قريب. تعمل في مجال PKI / PKI / تشفير كل يوم تقريبًا تتعامل مع هياكل ASN1 في شكل شهادات X509 وطلبات الشهادات وقوائم الشهادات الملغاة. والقائمة تطول. وهكذا ، أثناء العمل على أداة مساعدة لإنشاء طلب شهادة بتنسيق PKCS # 10 مع إنشاء زوج مفاتيح على رمز مميز / البطاقة الذكية PKCS # 11 ، كان من الطبيعي أن أقوم ، بشكل خاص ، بتكوين هيكل asn1 للمفتاح العمومي لكتابته على طلب الشهادة :

C-Sequence C-Sequence (<>) Object Identifier (<>) <oid public key> C-Sequence (<>) Object Identifier (<>) <oid  > Object Identifier (<>) <oid > Bit String (<>) <  > 

نظرًا لأننا استخدمنا رمز PKCS # 11 مع دعم التشفير الروسي كأداة لحماية معلومات التشفير ، فقد تم الحصول على المادة المصدر لهذا الهيكل من الرمز المميز وفقًا للقالب التالي:

  CK_BYTE gostr3410par[12]; CK_BYTE gostr3411par[12]; CK_ULONG gostr3410par_len; CK_ULONG gostr3411par_len; CK_BYTE pubkey[128]; CK_ULONG pubkeu_len; CK_KEY_TYPE key_type; CK_ATTRIBUTE templ_pk[] = { . . . {CKA_GOSTR3410PARAMS, gostr3410par, sizeof(gostr3410par)}, {CKA_GOSTR3411PARAMS, gostr3411par, sizeof(gostr3410par)}, {CKA_VALUE, pubkey, sizeof(pubkey)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)} } 

مباشرة من هذه البنية ، سيتم استخدام قيم السمة CKA_VALUE التي تحتوي على قيمة المفتاح العمومي وقيم CKA_GOSTR3410PARAMS و CKA_GOSTR3411PARAMS وسمات تحتوي على معرفات معلمة التوقيع ومعلمة التجزئة سيتم استخدامها لملء asn1-publickeyinfo.

تحدد السمة CKA_KEY_TYPE ، والتي يمكن أن تأخذ القيم CKK_GOSTR3410 و CKK_GOSTR3410_512 (في الحالات التي تستمر فيها خوارزمية توقيع GOST R 34.10-2001) غامضًا خوارزمية زوج المفاتيح. إذا كانت قيمة السمة CKA_KEY_TYPE هي CKK_GOSTR3410_512 ، فهي بالطبع تشير بشكل فريد إلى خوارزمية GOST R 34.10-2012 بطول مفتاح يبلغ 512 بت (معرف = 1.2.643.7.1.1.1.2). ولكن إذا كان يساوي CKK_GOSTR3410 ببساطة ، فهناك غموض حول نوع المفتاح الذي ينتمي إليه هذا المفتاح: GOST R 34.10-2001 أو ما زال GOST R 34.10-2012 بطول مفتاح يبلغ 256 بت. تساعد سمة CKA_GOSTR3411PARAMS في حل هذا الغموض.

على الفور ، نلاحظ أن المعلمات CKA_GOSTR3410PARAMS و CKA_GOSTR3411PARAMS على الرمز المميز وفقا لتوصيات TK-26 يتم تخزينها في شكل معرف كائن مشفر بواسطة oid ، على سبيل المثال:

\ x06 \ x06 \ x2a \ x85 \ x03 \ x02 \ x02 \ x13 ، حيث تحدد صفر بايت نوع التسلسل (0x06 هو معرف الكائن ، انظر الجدول أدناه) ، تشير البايتة الثانية إلى الطول (في الحالة العامة ، قد يستغرق الطول عدة بايت ، ولكن المزيد حول ذلك أدناه) حقل البيانات الذي يتم تخزين OID في شكل ثنائي.

إذا كانت هذه المعلمة تحتوي على oid لخوارزمية تجزئة GOST R 34.10-2012 بطول 256 بت (oid = 1.2.643.7.1.1.2.2 ، في شكل ثنائي "\ x2a \ x 85 \ x 03 \ x 07 \ x 01 \ x 01 \ x 02 \ x02 ") ، ثم يجب تعيين نوع المفتاح كـ GOST R 34.10-2012 بطول مفتاح يبلغ 256 بت. خلاف ذلك ، هو المفتاح GOST R 34.10-2001. قد تبدو الخوارزمية لتحديد نوع المفتاح كما يلي:

 . . . for (curr_attr_idx = 0; curr_attr_idx < (sizeof(templ_pk)/sizeof(templ_pk[0])); curr_attr_idx++){ curr_attr = &templ_pk[curr_attr_idx]; if (!curr_attr->pValue) { continue; } swith (curr_attr->type) { . . . case CKA_VALUE: /*  */ pubkey_len = curr_attr->ulValueLen; break; case CKA_GOSTR3410PARAMS: /*    */ gostr3410par_len = curr_attr->ulValueLen; break; case CKA_GOSTR3410PARAMS: /*   */ gostr3411par_len = curr_attr->ulValueLen; break; case CKA_KEY_TYPE: ulattr = curr_attr->pValue; if (*ulattr == CKK_GOSTR3410) { if (!memmem(gostr3411par), gostr3411par_len,"\x06\x08\x2a\x85\x03\x07", 6)) { /*    34.10-2001*/ strcpy(oid_key_type, "1.2.643.2.2.19"); memcpy(oid_key_type_asn1("\x06\x06\x2a\x85\x03\x02\x02\x13", 8); } else { /*    34.10-2012-256*/ strcpy(oid_key_type, ("1 2 643 7 1 1 1 1"); memcpy(oid_key_type_asn1 ("\x06\x08\x2a\x85\x03\x07\x01\x01\x01\x01", 10); } } else if (*ulattr == CKK_GOSTR3410_512) { /*    34.10-2012-512*/ strcpy(oid_key_type, ("1 2 643 7 1 1 1 2"); memcpy(oid_key_type_asn1 ("\x06\x08\x2a\x85\x03\x07\x01\x01\x01\x02", 10); } else { fprintf(stderr, "tclpkcs11_perform_pki_keypair CKK_GOSTR ERROR\n"); return (-1) } break; . . . } } . . . 

الآن لدينا جميع البيانات المصدر لإنشاء بنية المفتاح العمومي asn1.

تذكر أن كل عنصر في بنية asn1 يتكون من ثلاثة حقول:

  • ID.
  • طول حقل البيانات (بالبايت) ؛
  • مجال البيانات.

فيما يلي جدول ترميز لبعض أنواع المعرفات المستخدمة في PKI / PKI:

اكتب الاسموصف قصيراكتب التمثيل في ترميز DER
SEQUENCEيستخدم لوصف بنية البيانات التي تتكون من أنواع مختلفة.30
INTEGERعدد صحيح.02
معرف الهدفسلسلة من الأعداد الصحيحة.06
UTCTimeنوع مؤقت ، يحتوي على رقمين لتحديد السنة17
GeneralizedTimeنوع الوقت الممتد ، يحتوي على 4 أرقام للإشارة إلى السنة.18
SETوصف بنية البيانات من أنواع مختلفة.31
UTF8Stringيصف بيانات السلسلة.0C
NULLفي الواقع لاغية05
بت STRINGاكتب لتخزين سلسلة من البتات.03
اوكت STRINGاكتب لتخزين تسلسل بايت04

عند العمل مع asn1- الهياكل ، يحدث أكبر صدمة للمبتدئين بسبب طريقة ترميز طول حقل البيانات ، وخاصة عند تكوينه ، وإذا كنت تأخذ في الاعتبار بنية الكمبيوتر (littleendien ، bigendien). هذا هو العلم كله. وهكذا ، في عملية مناقشة الخوارزمية الخاصة بتكوين هذا الحقل ، تتبادر إلى الذهن الفكرة لاستخدام دالة sprintf ، التي ستأخذ بعين الاعتبار البنية ، وكيف يمكن تحديد عدد البايتات لتخزين الطول بواسطة رمز الوظيفة ، الذي يعد مخزنًا مؤقتًا به معرف نوع البيانات وطول البيانات:

 unsigned char *wrap_id_with_length(unsigned char type, //  unsigned long length, //  unsigned long *lenasn) //  asn1- { // unsigned long length; int buflen = 0; unsigned char *buf; char *format; char *buf_for_len[100]; const char *s; /*       */ char f0[] = "%02x%02x"; char f1[] = "%02x81%02x"; char f2[] = "%02x82%04x"; char f3[] = "%02x83%06x"; char f4[] = "%02x84%08x"; /*        */ buflen = ( length < 0x80 ? 1: length <= 0xff ? 2: length <= 0xffff ? 3: length <= 0xffffff ? 4: 5); /*   asn-*/ buf = malloc(length + buflen); // buf = malloc(buflen); /*        sprintf*/ switch (buflen - 1) { case 0: format = f0; break; case 1: format = f1; break; case 2: format = f2; break; case 3: format = f3; break; case 4: format = f4; break; } // sprintf    little  bigendian       sprintf((char*)buf_for_len, (const char *)format, type, length); length = 0; /* asn1-*/ fprintf(stderr, "ASN1 - :%s\n", buf_for_len); /*     */ for (s=(const char *)buf_for_len; *s; s +=2 ) { if (!hexdigitp (s) || (!hexdigitp (s+1) && hexdigitp (s+1) != 0) ){ fprintf (stderr, "invalid hex digits in \"%s\"\n", buf_for_len); *lenasn = 0; return NULL; } ((unsigned char*)buf)[length++] = xtoi_2 (s); } *lenasn = length; return (buf); } 

تقوم الدالة بإرجاع مؤشر إلى مخزن مؤقت بهيكل asn1 ، مخصص مع مراعاة طول البيانات. يبقى نسخ هذه البيانات إلى المخزن المؤقت المستلم مع إزاحة بواسطة طول الرأس. يتم إرجاع طول الرأس عبر المعلمة lenasn.

للتحقق من كيفية عمل هذه الوظيفة ، سنقوم بكتابة أداة بسيطة:

 #include <stdio.h> #include <stdlib.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)) int main (int argc, char *argv[]) { unsigned char *hdrasn; unsigned char type; unsigned long length; unsigned long lenasn; if (argc != 3) { fprintf (stderr, "Usage: wrap_id_with_length <id> <length>\n"); exit(-1); } type = atoi(argv[1]); length = atol(argv[2]); fprintf (stderr, "<id=%02x> <length=%lu>\n", type, length); if (length == 0) { fprintf (stderr, "Bad length=%s\nUsage: wrap_id_with_length <id> <length>\n", argv[2]); exit(-1); } hdrasn = wrap_id_with_length(type, length, &lenasn); fprintf (stderr, "Length asn1-buffer=%lu, LEN_HEADER=%lu, LEN_DATA=%lu\n", lenasn, lenasn - length, length); } 

احفظه مع دالة wrap_id_with_length في ملف wrap_id_with_length.c.

نبث:

 $cc –o wrap_id_with_length wrap_id_with_length.c $ 

قم بتشغيل البرنامج الناتج مع بيانات المصدر المختلفة. يتم تحديد نوع البيانات برقم عشري:

 bash-4.3$ ./wrap_id_with_length 06 8 <id=06> <length=8> ASN1 - :0608 Length asn1-buffer=10, LEN_HEADER=2, LEN_DATA=8 bash-4.3$ ./wrap_id_with_length 06 127 <id=06> <length=127> ASN1 - :067f Length asn1-buffer=129, LEN_HEADER=2, LEN_DATA=127 bash-4.3$ ./wrap_id_with_length 48 128 <id=30> <length=128> ASN1 - :308180 Length asn1-buffer=131, LEN_HEADER=3, LEN_DATA=128 bash-4.3$ ./wrap_id_with_length 48 4097 <id=30> <length=4097> ASN1 - :30821001 Length asn1-buffer=4101, LEN_HEADER=4, LEN_DATA=4097 bash-4.3$ 

يمكنك التحقق من صحة تكوين الرأس باستخدام أي آلة حاسبة:



نحن جميعا على استعداد لتشكيل أي هيكل ASN1. لكن أولاً ، قم بإجراء تغييرات صغيرة على الدالة wrap_id_with_length واتصل بها

wrap_for_asn1:
 unsigned char *wrap_for_asn1(unsigned char type, unsigned char *prefix, unsigned long prefix_len, unsigned char *wrap, unsigned long wrap_len, unsigned long *lenasn){ unsigned long length; int buflen = 0; unsigned char *buf; char *format; const char buf_for_len[100]; const char *s; char f0[] = "%02x%02x"; char f1[] = "%02x81%02x"; char f2[] = "%02x82%04x"; char f3[] = "%02x83%06x"; char f4[] = "%02x84%08x"; length = prefix_len + wrap_len; buflen += ( length <= 0x80 ? 1: length <= 0xff ? 2: length <= 0xffff ? 3: length <= 0xffffff ? 4: 5); buf = malloc(length + buflen); switch (buflen - 1) { case 0: format = f0; break; case 1: format = f1; break; case 2: format = f2; break; case 3: format = f3; break; case 4: format = f4; break; } // sprintf    little  bigendian    sprintf((char*)buf_for_len, (const char *)format, type, length); length = 0; for (s=buf_for_len; *s; s +=2 ) { if (!hexdigitp (s) || (!hexdigitp (s+1) && hexdigitp (s+1) != 0) ){ fprintf (stderr, "invalid hex digits in \"%s\"\n", buf_for_len); } ((unsigned char*)buf)[length++] = xtoi_2 (s); } if (prefix_len > 0) { memcpy(buf + length, prefix, prefix_len); } memcpy(buf + length + prefix_len, wrap, wrap_len); *lenasn = (unsigned long)(length + prefix_len + wrap_len); return (buf); } 


كما ترون ، التغييرات ضئيلة. كمعلمات إدخال ، تتم إضافة البيانات نفسها ، والتي يتم تعبئتها داخل الوظيفة في بنية asn1. علاوة على ذلك ، يمكن تغذية المخزن المؤقت جهازي الإدخال في وقت واحد. يبدو لنا مريحة.

قبل تقديم حالة اختبار ، نعطي رموز ثلاث وظائف أخرى. تحول أول وظيفة oid2buffer oid s من الشكل العشري المنقط إلى تشفير DER. نحن بحاجة إلى هذه الوظيفة لتحويل ، على وجه الخصوص ، oids لزوج المفاتيح (انظر أعلاه).

نص الوظيفة هنا:
static char * oid2buffer (char * oid_str، long ligned * len) {
char * curstr؛
char * curstr1 ؛
char * nextstr؛
غير موقعة firstval ؛
غير موقعة secondval ؛
كثافة العمليات غير الموقعة ؛
غير موقعة شار بوف [5] ؛
عدد العد
char oid_hex غير موقعة [100] ؛
شار * الدقة ؛
أنا
if (oid_str == NULL) {
* لين = 0 ؛
إرجاع NULL؛
}
* لين = 0 ؛
curstr = strdup ((const char *) oid_str)؛
curstr1 = curstr.
nextstr = strchr (curstr، '.')؛
if (nextstr == NULL) {
* لين = 0 ؛
إرجاع NULL؛
}
* nextstr = '\ 0' ؛
firstval = atoi (curstr) ؛
curstr = nextstr + 1؛
nextstr = strchr (curstr، '.')؛
إذا (nextstr) {
* nextstr = '\ 0' ؛
}
secondval = atoi (curstr) ؛
if (firstval> 2) {
* لين = 0 ؛
إرجاع NULL؛
}
إذا (الثانية)> 39) {
* لين = 0 ؛
إرجاع NULL؛
}
oid_hex [0] = (char غير موقعة) ((firstval * 40) + secondval) ؛
أنا = 1 ؛
بينما (nextstr) {
curstr = nextstr + 1؛

nextstr = strchr (curstr، '.')؛

إذا (nextstr) {
* nextstr = '\ 0' ؛
}

memset (buf، 0، sizeof (buf))؛
val = atoi (curstr) ؛
العد = 0 ؛
إذا (curstr [0]! = '0')
بينما (فال) {
buf [count] = (val & 0x7f)؛
فال = فال >> 7 ؛
عد ++؛
}
آخر
buf [count] = (val & 0x7f)؛
فال = فال >> 7 ؛
عد ++؛
}
بينما (العد--) {
إذا (العد) {
oid_hex [i] = buf [count] | 0x80.
} آخر {
oid_hex [i] = buf [count]؛
}
أنا ++ ؛
}
}
res = (char *) malloc (i)؛
إذا (الدقة) {
memcpy (res، oid_hex، i)؛
* لين = أنا ؛
}
مجانا (curstr1) ؛
عودة الدقة ؛
}

تسمح الدالتين الأخريين بتحويل المخزن المؤقت الثنائي إلى عدد ست عشري (buffer2hex) والعكس (hex2buffer).

هذه الوظائف هنا:
شار ثابت *
buffer2hex (تابع char * src ، size_t len)
{
أنا
شار * د.
شار * الدقة ؛
dest = (char *) malloc (len * 2 + 1) ؛
الدقة = dest ؛
إذا (dest)
{
لـ (i = 0 ؛ i <len ؛ i ++ ، dest + = 2)
sprintf (dest، "٪ 02X"، src [i])؛
}
عودة الدقة ؛
}

فراغ ثابت *
hex2buffer (const char * string، size_t * r_length)
{
كون تشار شار
شار * العازلة غير موقعة ؛
size_t طول ؛

العازلة = malloc (strlen (سلسلة) / 2 + 1) ؛
طول = 0 ؛
من أجل (s = string؛ * s؛ s + = 2)
{
إذا (! hexdigitp (s) ||! hexdigitp (s + 1)) {
fprintf (stderr ، "أرقام ست عشرية غير صالحة في \"٪ s \ "\ n" ، السلسلة) ؛
}
((char * غير مؤقت)) [طول ++] = xtoi_2 (s) ؛
}
* r_length = الطول ؛
عودة العازلة.
}

هذه الوظائف مريحة للغاية للتصحيح ، وغالبًا ما يكون لدى الكثير منها.

والآن نعود إلى حل المهمة ، والحصول على بنية asn1 للمفتاح العمومي. سنكتب أداة مساعدة ستنشئ وتحفظ asn1- بنية المفتاح العمومي في الملف ASN1_PIBINFO.der.

تقع هذه الأداة هنا:
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdint.h> #include <string.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)) /*   oid2buffer*/ /*   buffer2hex  hex2buffer*/ /*   wrap_for_asn1*/ int main() { int fd; unsigned char *asn, *asn1, *asn2, *asn3, *pubkeyalgo; unsigned char* pubkey_bin; //  char gost3410par[] = "\x06\x7\x2a\x85\x03\x02\x02\x23\x01"; unsigned long gost3410par_len = sizeof(gost3410par) - 1; char gost3411par[] = "\x06\x8\x2a\x85\x03\x07\x01\x01\x02\x02"; unsigned long gost3411par_len = sizeof(gost3411par) - 1; unsigned char pubkey_hex[] = "9af03570ed0c54cd4953f11ab19e551022cd48603326c1b9b630b1cff74e5a160ba1718166cc22bf70f82bdc957d924c501b9332491cb3a36ce45770f05487b5"; char pubkey_oid_2001[] = "1.2.643.2.2.19"; char pubkey_oid_2012_256[] = "1.2.643.7.1.1.1.1"; char pubkey_oid_2012_512[] = "1.2.643.7.1.1.1.2"; unsigned long pubkey_len, pubkey_len_full, len10, len11, len12, lenalgo; unsigned char *pkalgo; unsigned long pkalgo_len; uint16_t x = 1; /* 0x0001 */ printf("%s\n", *((uint8_t *) &x) == 0 ? "big-endian" : "little-endian"); ////pubkeyinfo //      if (!memmem(gost3411par, 8, "\x2a\x85\x03\x07", 4)) { //   34.11-94,     34.10-2001 - 1.2.643.2.2.19 pubkeyalgo = (unsigned char *)oid2buffer(pubkey_oid_2001, &lenalgo); } else if (!memcmp(gost3411par, "\x2a\x85\x03\x07\x01\x01\x02\x02", 8)){ //   34.11-2012-256,     34.10-2012-256 - 1.2.643.7.1.1.1.1 pubkeyalgo = (unsigned char *)oid2buffer(pubkey_oid_2012_256, &lenalgo); } else { //   34.11-2012-512,     34.10-2012-512 - 1.2.643.7.1.1.1.2 pubkeyalgo = (unsigned char *)oid2buffer(pubkey_oid_2012_512, &lenalgo); } pubkey_bin =(unsigned char*)hex2buffer((const char *)pubkey_hex, &pubkey_len); //    asn1 = wrap_for_asn1_bin('\x04', (unsigned char *)"", 0, pubkey_bin, pubkey_len, &pubkey_len); asn = wrap_for_asn1_bin('\x03', (unsigned char *)"\x00", 1, asn1, pubkey_len, &pubkey_len_full); fprintf(stderr, "PUBLIC_VALUE=%s\n", buffer2hex(asn, pubkey_len_full)); free(asn1); //  asn3 = wrap_for_asn1_bin('\x30', (unsigned char*)gost3410par, gost3410par_len, (unsigned char *)gost3411par, gost3411par_len, &len12); fprintf(stderr, "\nPARAMS len12=%lu, FULL=%s\n", len12, buffer2hex(asn3, len12)); //   pkalgo = wrap_for_asn1_bin('\x06', (unsigned char *)"", 0, pubkeyalgo, lenalgo, &pkalgo_len); //     asn2 = wrap_for_asn1_bin('\x30', pkalgo, pkalgo_len, asn3, len12, &len11); fprintf(stderr, "PubKEY=%s\n", buffer2hex(asn3, len11)); asn1 = wrap_for_asn1_bin('\x30', asn2, len11, asn, pubkey_len_full, &len10); free(asn2); free(asn3); fprintf(stderr, "\n%s\n", buffer2hex(asn1, len10)); fd = open ("ASN1_PUBINFO.der", O_TRUNC|O_RDWR|O_CREAT,S_IRWXO); write(fd, asn1, len10); close(fd); free(asn1); chmod("ASN1_PUBINFO.der", 0666); } 


للتحقق من النتيجة ، سوف نستخدم الأدوات المساعدة derdump و pp من حزمة NSS.

الأداة الأولى ستظهر لنا بنية asn1 للمفتاح العمومي:

 $ derdump -i ASN1_PUBINFO.der C-Sequence (102) C-Sequence (31) Object Identifier (8) 1 2 643 7 1 1 1 2 (GOST R 34.10-2012 Key 512) C-Sequence (19) Object Identifier (7) 1 2 643 2 2 35 1 Object Identifier (8) 1 2 643 7 1 1 2 2 (GOST R 34.11-2012 256) Bit String (67) 00 04 40 9a f0 35 70 ed 0c 54 cd 49 53 f1 1a b1 9e 55 10 22 cd 48 60 33 26 c1 b9 b6 30 b1 cf f7 4e 5a 16 0b a1 71 81 66 cc 22 bf 70 f8 2b dc 95 7d 92 4c 50 1b 93 32 49 1c b3 a3 6c e4 57 70 f0 54 87 b5 $ 

سيظهر الثاني محتويات المفتاح:

 $ pp -t pk -i ASN1_PUBINFO.der Public Key: Subject Public Key Info: Public Key Algorithm: GOST R 34.10-2012 512 Public Key: PublicValue: 9a:f0:35:70:ed:0c:54:cd:49:53:f1:1a:b1:9e:55:10: 22:cd:48:60:33:26:c1:b9:b6:30:b1:cf:f7:4e:5a:16: 0b:a1:71:81:66:cc:22:bf:70:f8:2b:dc:95:7d:92:4c: 50:1b:93:32:49:1c:b3:a3:6c:e4:57:70:f0:54:87:b5 GOSTR3410Params: OID.1.2.643.2.2.35.1 GOSTR3411Params: GOST R 34.11-2012 256 $ 

يمكن لأولئك الذين يرغبون في الاختيار المزدوج ، على سبيل المثال ، باستخدام أداة openssl ، ويفضل باستخدام محرك GOST متصل :

 $ /usr/local/lirssl_csp_64/bin/lirssl_static asn1parse -inform DER -in ASN1_PUBINFO.der 0:d=0 hl=2 l= 102 cons: SEQUENCE 2:d=1 hl=2 l= 31 cons: SEQUENCE 4:d=2 hl=2 l= 8 prim: OBJECT :GOST R 34.10-2012 with 512 bit modulus 14:d=2 hl=2 l= 19 cons: SEQUENCE 16:d=3 hl=2 l= 7 prim: OBJECT :id-GostR3410-2001-CryptoPro-A-ParamSet 25:d=3 hl=2 l= 8 prim: OBJECT :GOST R 34.11-2012 with 256 bit hash 35:d=1 hl=2 l= 67 prim: BIT STRING $ 

كما ترون ، تم اختبار بنية ASN1 الناتجة بنجاح في كل مكان.

لا تتطلب الخوارزمية والأداة المقترحة لتشكيل هياكل asn1 استخدام أي مترجمين ASN1 ومكتبات الإمتداد (نفس opensl) وتبين أنها ملائمة للغاية للاستخدام. سوف نتذكرها في المقالة التالية ، عندما يتم تحقيق رغبات Pas وسيتم تقديم أداة رسومية لا تقوم فقط "بتوزيع الشهادات" والتحقق من صحتها ، ولكن أيضًا تنشئ زوجًا رئيسيًا على الرموز PKCS # 11 ، وتولد وتوقع طلبًا لشهادة مؤهلة. مع هذا الطلب ، يمكنك الذهاب بأمان إلى المرجع المصدق للحصول على شهادة. قبل الأسئلة ، لاحظت على الفور أنه في الحالة الأخيرة ، يجب أن يتم اعتماد الرمز المميز كنظام لحماية معلومات التشفير في نظام شهادات FSB في روسيا.

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


All Articles