
Die ASN.1-Transportsyntax definiert eine einzigartige Methode zum Konvertieren von Werten von Variablen gültigen Typs in eine Folge von Bytes zur Übertragung über ein Netzwerk. In ASN.1 heißt es Basic Encoding Rules (BER). Regeln sind rekursiv, daher ist das Codieren von zusammengesetzten Objekten eine Verkettung von codierten Sequenzen von Komponentenobjekten. Das ASN.1-Protokoll beschreibt die Datenstruktur in einer
einfachen und verständlichen Sprache .
Jeder übertragene Wert - sowohl der Basiswert als auch der abgeleitete Typ - besteht aus drei Feldern:
- Kennung;
- Datenfeldlänge (in Bytes);
- Datenfeld.
Wenn Sie immer die Länge des Datenfelds angeben (ich halte dies für eine gute Vorgehensweise), wird das Flag am Ende des Datenfelds nicht verwendet.
Es gibt viele verschiedene kostenpflichtige und kostenlose Compiler für ASN.1 für verschiedene Programmiersprachen, aber wir möchten etwas sehr Einfaches zur Hand haben.
Die überwiegende Mehrheit der Softwareentwickler findet den
ASN.1- Standardkomplex. Das habe ich mir bis vor kurzem auch gedacht. Sie arbeiten fast täglich im Bereich PKI / PKI / Kryptographie und beschäftigen sich mit ASN1-Strukturen in Form von X509-Zertifikaten, Zertifikatsanforderungen und Listen widerrufener Zertifikate. Und die Liste geht weiter. Während ich an einem Dienstprogramm zum Erstellen einer Zertifikatanforderung im PKCS # 10-Format mit dem Generieren eines Schlüsselpaars auf einem PKCS # 11-Token / einer Smartcard arbeitete, musste ich natürlich insbesondere die asn1-Struktur des öffentlichen Schlüssels bilden, um sie in die Zertifikatanforderung zu schreiben ::
C-Sequence C-Sequence (<>) Object Identifier (<>) <oid public key> C-Sequence (<>) Object Identifier (<>) <oid > Object Identifier (<>) <oid > Bit String (<>) < >
Da wir das PKCS # 11-Token mit Unterstützung der russischen Kryptographie als kryptografisches Informationsschutzwerkzeug verwendet haben, wurde das Quellmaterial für diese Struktur aus dem Token gemäß der folgenden Vorlage erhalten:
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)} }
Direkt aus dieser Struktur werden die Werte des Attributs CKA_VALUE, das den Wert des öffentlichen Schlüssels enthält, und die Werte der Attribute CKA_GOSTR3410PARAMS und CKA_GOSTR3411PARAMS, die die Oids des Signaturparameters und des Hash-Parameters enthalten, zum Ausfüllen von asn1-publickeyinfo verwendet.
Das Attribut CKA_KEY_TYPE, das die Werte CKK_GOSTR3410 und CKK_GOSTR3410_512 annehmen kann (unter den Bedingungen, unter denen der Signaturalgorithmus von GOST R 34.10-2001 weiterhin funktioniert), definiert den Schlüsselpaaralgorithmus mehrdeutig. Wenn der Wert des Attributs CKA_KEY_TYPE gleich CKK_GOSTR3410_512 ist, zeigt er natürlich eindeutig auf den Algorithmus GOST R 34.10-2012 mit einer Schlüssellänge von 512 Bit (oid = 1.2.643.7.1.1.1.2). Wenn es jedoch einfach gleich CKK_GOSTR3410 ist, besteht Unklarheit darüber, zu welchem Schlüsseltyp dieser Schlüssel gehört: GOST R 34.10-2001 oder es ist immer noch GOST R 34.10-2012 mit einer Schlüssellänge von 256 Bit. Das Attribut CKA_GOSTR3411PARAMS hilft, diese Mehrdeutigkeit zu beheben.
Wir stellen sofort fest, dass die Parameter CKA_GOSTR3410PARAMS und CKA_GOSTR3411PARAMS auf dem Token gemäß den Empfehlungen von TK-26 als von oid codierte Objektkennung gespeichert werden, zum Beispiel:
\ x06 \ x06 \ x2a \ x85 \ x03 \ x02 \ x02 \ x13, wobei das Nullbyte den Sequenztyp bestimmt (0x06 ist die Objektkennung, siehe Tabelle unten), das zweite Byte die Länge angibt (im allgemeinen Fall kann die Länge mehrere Bytes dauern). aber mehr dazu weiter unten) das Datenfeld, in dem oid in binärer Form gespeichert ist.
Wenn dieser Parameter die oid des Hash-Algorithmus GOST R 34.10-2012 mit einer Länge von 256 Bit enthält (oid = 1.2.643.7.1.1.2.2, in binärer Form "\ x2a \ x 85 \ x 03 \ x 07 \ x 01 \ x 01 \ x 02 \ x02 "), dann muss der Schlüsseltyp als GOST R 34.10-2012 mit einer Schlüssellänge von 256 Bit eingestellt werden. Ansonsten ist es der Schlüssel von GOST R 34.10-2001. Der Algorithmus zum Bestimmen des Schlüsseltyps kann folgendermaßen aussehen:
. . . 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)) { 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 { 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) { 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; . . . } } . . .
Jetzt haben wir alle Quelldaten zum Erstellen der öffentlichen Schlüsselstruktur asn1.
Denken Sie daran, dass jedes Element der asn1-Struktur aus drei Feldern besteht:
- Kennung;
- Datenfeldlänge (in Bytes);
- Datenfeld.
Hier ist
eine Codierungstabelle für einige Arten von Bezeichnern, die in PKI / PKI verwendet werden:
Typ Name | Kurzbeschreibung | Typdarstellung in DER-Codierung |
---|
Sequenz | Wird verwendet, um eine Datenstruktur zu beschreiben, die aus verschiedenen Typen besteht. | 30 |
INTEGER | Ganze Zahl. | 02 |
OBJECT IDENTIFIER | Eine Folge von ganzen Zahlen. | 06 |
UTCTime | Temporärer Typ, enthält 2 Ziffern zur Bestimmung des Jahres | 17 |
Generalisierte Zeit | Erweiterter Zeittyp, enthält 4 Ziffern zur Angabe des Jahres. | 18 |
SET | Beschreibt die Datenstruktur verschiedener Typen. | 31 |
UTF8String | Beschreibt Zeichenfolgendaten. | 0C |
Null | Eigentlich NULL | 05 |
BIT STRING | Typ zum Speichern einer Folge von Bits. | 03 |
OCTET STRING | Typ zum Speichern einer Folge von Bytes | 04 |
Bei der Arbeit mit asn1-Strukturen wird der größte Schock für Uneingeweihte durch die Methode zum Codieren der Länge des Datenfelds verursacht, insbesondere beim Bilden, und wenn Sie die Computerarchitektur (littleendien, bigendien) berücksichtigen. Das ist eine ganze
Wissenschaft . Bei der Erörterung des Algorithmus zur Bildung dieses Feldes kam mir die Idee, die Sprintf-Funktion zu verwenden, die selbst die Architektur berücksichtigt, und wie die Anzahl der Bytes zum Speichern der Länge bestimmt wird, zeigt der Funktionscode, der einen Puffer mit dem Datentypbezeichner und der Datenlänge erstellt:
unsigned char *wrap_id_with_length(unsigned char type,
Die Funktion gibt einen Zeiger auf einen Puffer mit einer asn1-Struktur zurück, der unter Berücksichtigung der Länge der Daten zugewiesen wird. Es bleibt, diese Daten mit einem Versatz um die Länge des Headers in den empfangenen Puffer zu kopieren. Die Länge des Headers wird über den Parameter lenasn zurückgegeben.
Um zu überprüfen, wie diese Funktion funktioniert, schreiben wir ein einfaches Dienstprogramm:
#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); }
Speichern Sie es zusammen mit der Funktion wrap_id_with_length in der Datei wrap_id_with_length.c.
Wir senden:
$cc –o wrap_id_with_length wrap_id_with_length.c $
Führen Sie das resultierende Programm mit verschiedenen Quelldaten aus. Der Datentyp wird durch eine Dezimalzahl angegeben:
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$
Sie können die Richtigkeit der Bildung des Headers mit einem beliebigen Taschenrechner überprüfen:

Wir sind alle bereit, jede ASN1-Struktur zu bilden. Nehmen Sie jedoch zuerst kleine Änderungen an der Funktion wrap_id_with_length vor und rufen Sie sie auf
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; }
Wie Sie sehen können, sind die Änderungen minimal. Als Eingabeparameter werden die Daten selbst hinzugefügt, die innerhalb der Funktion in eine asn1-Struktur gepackt werden. Darüber hinaus können dem Eingang zwei Puffer gleichzeitig zugeführt werden. Es scheint uns bequem.
Bevor wir einen Testfall präsentieren, geben wir die Codes von drei weiteren Funktionen an. Die erste
oid2buffer- Funktion konvertiert
oids von der gepunkteten Dezimalform in die DER-Codierung. Wir benötigen diese Funktion, um insbesondere Oids des Schlüsselpaars zu konvertieren (siehe oben).
Der Funktionstext ist hier:statischer char * oid2buffer (char * oid_str, unsigned long * len) {
char * curstr;
char * curstr1;
char * nextstr;
unsigned int firstval;
unsigned int secondval;
unsigned int val;
vorzeichenloser char buf [5];
int count;
unsigned char oid_hex [100];
char * res;
int i;
if (oid_str == NULL) {
* len = 0;
return NULL;
}}
* len = 0;
curstr = strdup ((const char *) oid_str);
curstr1 = curstr;
nextstr = strchr (curstr, '.');
if (nextstr == NULL) {
* len = 0;
return NULL;
}}
* nextstr = '\ 0';
firstval = atoi (curstr);
curstr = nextstr + 1;
nextstr = strchr (curstr, '.');
if (nextstr) {
* nextstr = '\ 0';
}}
secondval = atoi (curstr);
if (firstval> 2) {
* len = 0;
return NULL;
}}
if (secondval> 39) {
* len = 0;
return NULL;
}}
oid_hex [0] = (vorzeichenloses Zeichen) ((erster Wert * 40) + zweiter Wert);
i = 1;
while (nextstr) {
curstr = nextstr + 1;
nextstr = strchr (curstr, '.');
if (nextstr) {
* nextstr = '\ 0';
}}
Memset (buf, 0, sizeof (buf));
val = atoi (curstr);
count = 0;
if (curstr [0]! = '0')
while (val) {
buf [count] = (val & 0x7f);
val = val >> 7;
count ++;
}}
sonst {
buf [count] = (val & 0x7f);
val = val >> 7;
count ++;
}}
while (count--) {
if (count) {
oid_hex [i] = buf [count] | 0x80;
} else {
oid_hex [i] = buf [count];
}}
i ++;
}}
}}
res = (char *) malloc (i);
if (res) {
memcpy (res, oid_hex, i);
* len = i;
}}
frei (curstr1);
return res;
}}
Mit den beiden anderen Funktionen kann der Binärpuffer in eine Hexadezimalzahl (buffer2hex) konvertiert werden und umgekehrt (hex2buffer).
Diese Funktionen sind hier:statisches Zeichen *
buffer2hex (const unsigned char * src, size_t len)
{
int i;
char * dest;
char * res;
dest = (char *) malloc (len * 2 + 1);
res = dest;
if (dest)
{
für (i = 0; i <len; i ++, dest + = 2)
sprintf (dest, "% 02X", src [i]);
}}
return res;
}}
statische Leere *
hex2buffer (const char * string, size_t * r_length)
{
const char * s;
vorzeichenloser char * -Puffer;
size_t Länge;
buffer = malloc (strlen (string) / 2 + 1);
Länge = 0;
für (s = string; * s; s + = 2)
{
if (! hexdigitp (s) ||! hexdigitp (s + 1)) {
fprintf (stderr, "ungültige Hex-Ziffern in"% s "\ n", Zeichenfolge);
}}
((vorzeichenloser char *) Puffer) [Länge ++] = xtoi_2 (s);
}}
* r_length = Länge;
Rückgabepuffer;
}}
Diese Funktionen sind sehr praktisch für das Debuggen, und höchstwahrscheinlich haben viele sie.
Und jetzt kehren wir zur Lösung der Aufgabe zurück und erhalten eine asn1-Struktur des öffentlichen Schlüssels. Wir werden ein Dienstprogramm schreiben, das die asn1-Struktur des öffentlichen Schlüssels in der Datei ASN1_PIBINFO.der generiert und speichert.
Dieses Dienstprogramm befindet sich hier: #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); }
Um das Ergebnis zu überprüfen, verwenden wir die Dienstprogramme derdump und pp aus dem NSS-Paket.
Das erste Dienstprogramm zeigt uns die asn1-Struktur des öffentlichen Schlüssels:
$ 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 $
Die zweite zeigt den Inhalt des Schlüssels:
$ 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 $
Wer möchte, kann dies beispielsweise mit dem Dienstprogramm openssl, vorzugsweise mit einer
angeschlossenen GOST- Engine, überprüfen:
$ /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 $
Wie Sie sehen können, wird die resultierende ASN1-Struktur überall erfolgreich getestet.
Der vorgeschlagene Algorithmus und das vorgeschlagene Dienstprogramm zum Bilden von asn1-Strukturen erfordern keine Verwendung von ASN1-Compilern und Erweiterungsbibliotheken (das gleiche openssl) und erwiesen sich als sehr bequem zu verwenden. Wir werden sie im nächsten Artikel zurückrufen, wenn
Pas- Wünsche erfüllt werden und ein grafisches Dienstprogramm vorgestellt wird, das nicht nur Zertifikate analysiert und deren Gültigkeit überprüft, sondern auch ein Schlüsselpaar für PKCS # 11-Token generiert, eine Anforderung für ein qualifiziertes Zertifikat generiert und signiert. Mit dieser Anforderung können Sie sicher zur Zertifizierungsstelle gehen, um ein Zertifikat zu erhalten. Vor den Fragen stelle ich sofort fest, dass im letzteren Fall das Token als kryptografisches Informationsschutzsystem im Zertifizierungssystem des FSB von Russland zertifiziert sein muss.