Einführung

Das Kerberos 5-Protokoll wird jetzt aktiv zur Authentifizierung verwendet. Ein Merkmal dieses Protokolls ist, dass es eine Authentifizierung basierend auf vier Säulen durchführt:
- Symmetrische Verschlüsselung;
- Hashing
- EDS;
- Dritte vertrauenswürdige Partei.
Ab der fünften Version ist es jetzt möglich, eine asymmetrische Verschlüsselung (für die elektronische Signatur) zu verwenden. Es ist nicht sinnvoll, sich mit der Funktionsweise des Kerberos-Protokolls zu befassen, da die Beschreibung des Algorithmus hier zu finden ist .
Leider ist die Anzahl der von diesem Protokoll verwendeten Verschlüsselungs-, Hashing- und digitalen Signaturalgorithmen nicht so groß, wie ich es gerne hätte. Daher möchte ich in diesem Artikel zeigen, wie man sie hinzufügt leicht und einfach eigene Algorithmen zur Implementierung dieses Protokolls durch das MIT . Wir werden unsere inländischen Algorithmen hinzufügen: GOST 28147-89 (alias Magma), GOST R 34.11-2012 (alias Stribog) und GOST R 34.10-2012 (ich hätte auch gerne aka dafür, aber ich weiß nicht :(). Bereit Eine Lösung für diese Algorithmen finden Sie in meinem Repository . Auf der Client-Seite werden wir Hardware-Implementierungen von GOST-Algorithmen in Rutoken EDS 2.0 und deren Software-Implementierungen in Engine GOST für openssl verwenden. Die sicherste Option zum Speichern von Schlüsseln ist jedoch, wenn sie direkt auf Rutoken generiert werden und niemals Verlassen Sie sein Gedächtnis nicht während kryptografischer Operationen Für diese Option ist ein Motor erforderlich.
Bevor wir mit der Implementierung der Algorithmen beginnen, beschreiben wir die wichtigsten Stellen, an denen Änderungen vorgenommen werden. Im Verzeichnis src / lib / crypto / befinden sich die Implementierungen aller Algorithmen, die für die symmetrische Kryptographie und das Hashing verantwortlich sind. Es gibt zwei Implementierungen dieser kryptografischen Algorithmen: integrierte und openssl. Um Zeit und Platz zu sparen, werden wir natürlich die Implementierung von Algorithmen mit openssl hinzufügen, in denen sie bereits existieren (na ja, oder fast da, aber dazu später mehr). Um asymmetrische Algorithmen hinzuzufügen, müssen Sie das Plugin src / plugins / preauth / pkinit optimieren
Wenn Sie Kerberos noch nicht konfiguriert haben, finden Sie hier Anweisungen zur Erstkonfiguration und zum Betrieb. Außerdem geht der Autor davon aus, dass Sie mit der Domain AKTIV-TEST.RU arbeiten
Hinzufügen von Hash-Algorithmen und symmetrischer Verschlüsselung
Wie bereits angekündigt, werden wir Verschlüsselungs- und Hashing-Algorithmen nicht von Grund auf neu schreiben, sondern eine vorgefertigte Implementierung dieser Algorithmen in openssl verwenden. Openssl unterstützt direkt nicht die Implementierung von inländischen Algorithmen, ist jedoch in dieser Hinsicht mobil und ermöglicht das Hinzufügen neuer Algorithmen mithilfe des GOST-Mechanismus der Engine für die Arbeit mit Schlüsseln im Dateisystem, die auf der Token-Engine gespeichert sind.
Eine kleine Einführung in den OpenSL-Motor und den Anschluss des Motors GOST
Engine in openssl ist eine kleine dynamische Bibliothek, die openssl bei Bedarf in die Laufzeit lädt. Jede solche Bibliothek muss bestimmte Symbole (Funktionen) enthalten, um die erforderlichen Algorithmen zu laden. In diesem Artikel verwenden wir Engine Gost, das alle erforderlichen inländischen kryptografischen Algorithmen enthält.
Die Installation ist beispielsweise sehr einfach und läuft wie folgt ab:
Laden Sie die Implementierung dieser Engine aus dem Repository herunter.
baue damit eine Bibliothek (mkdir build && cd build && cmake ... && make):
mkdir build cd build cmake .. make
Im bin-Verzeichnis (DAS IM ROOT-KATALOG DES PROJEKTS ERSCHEINT !!!) befindet sich eine dynamische Bibliothek gost.so - das ist unser Engin. Es muss in das Verzeichnis verschoben werden, in dem die openssl-Engines gespeichert sind. Finden Sie den Speicherort dieses Verzeichnisses heraus mit:
openssl version -a | grep ENGINESDIR
Es liegt an letzterem - Sie müssen openssl mitteilen, wo sich die angegebene Engine befindet und wie sie heißt. Sie können dies tun, indem Sie die Konfigurationsdatei openssl.cnf ändern. Der Standort kann gefunden werden mit:
openssl version -a | grep OPENSSLDIR
Am Ende dieser Datei müssen Sie den folgenden Inhalt hinzufügen:
Danach sollte diese Engine in openssl erscheinen. Sie können die Leistung überprüfen, indem Sie beispielsweise erzwingen, einen privaten Schlüssel in einer Datei gemäß GOST R 34.10-2012 zu generieren:
openssl genpkey -engine gost -algorithm gost2012_512 -pkeyopt paramset:A -out client_key.pem
Das Flag -engine gibt lediglich an, welche Engine vor Arbeitsbeginn geladen werden muss, damit der Algorithmus zur Schlüsselgenerierung für GOST R 34.10-2012 sichtbar wird.
Implementierung des Hash-Algorithmus
Beginnen wir mit dem Einfachsten - mit der Implementierung des Stribog-Algorithmus. Kerberos hat eine starke Verbindung zwischen den Hashing- und Verschlüsselungsalgorithmen. Das heißt, Sie können nicht einfach einen Algorithmus für die Verschlüsselung auswählen und für das Hashing eines anderen müssen Sie den Hash- und Verschlüsselungsalgorithmus integrieren. Der Grund dafür ist mir nicht bekannt, aber da solche Regeln dort existieren, versuchen wir, eine Kombination aus dem Stribog-Algorithmus und AES zu erstellen.
Weil Wir brauchen Vertrauen in die Verbindung an verschiedenen Stellen unseres Programms. Erstellen wir zunächst eine kleine gost_helper- Bibliothek, die die Initialisierungsfunktion der Engine in openssl enthält, sowie einige Funktionen, die der Einfachheit halber Kontexte einiger Hashing-Algorithmen zurückgeben - dies wird uns in Zukunft helfen. Wir benennen diese Bibliothek gost_helper und erstellen einen entsprechenden Header und eine Quelldatei dafür im Verzeichnis src / lib / crypto / openssl / :
// gost_helper.h #include <openssl/evp.h> // GOST void krb5int_init_gost(); // , const EVP_MD * EVP_gostR3411_2012_256(); const EVP_MD * EVP_gostR3411_2012_512(); // gost_helper.c #include "gost_helper.h" #include <openssl/engine.h> // static ENGINE *eng = NULL; void krb5int_init_gost() { // , if (eng) return; OPENSSL_add_all_algorithms_conf(); ERR_load_crypto_strings(); if (!(eng = ENGINE_by_id("gost"))) { printf("Engine gost doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); } const EVP_MD * EVP_gostR3411_2012_256() { krb5int_init_gost(); return EVP_get_digestbynid(NID_id_GostR3411_2012_256); } const EVP_MD * EVP_gostR3411_2012_512() { krb5int_init_gost(); return EVP_get_digestbynid(NID_id_GostR3411_2012_512); }
Nach dem Hinzufügen der Hilfsbibliothek müssen Sie ihre Existenz im Makefile deklarieren und ihre Dateiabhängigkeiten ausschreiben. Fügen Sie dazu Folgendes hinzu:
Es ist erwähnenswert, dass wir in Zukunft beim Verbinden dieser Bibliothek die Abhängigkeiten einiger Dateien zum Header dieser Bibliothek hinzufügen müssen. Dies geschieht sehr einfach - das Ziel wird gefunden, bei dem Sie die Abhängigkeit in die deps-Datei einfügen müssen und die Abhängigkeit von rel / path / to / gost_helper.h aufgezeichnet wird . In src / lib / crypto / openssl / hash_provider / deps müssten Sie beispielsweise Folgendes hinzufügen:
hash_evp.so hash_evp.po $(OUTPRE)hash_evp.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ ... $(srcdir)/../gost_helper.h hash_evp.c
Um Platz im Artikel zu sparen und Ihr Gehirn zu dehnen, werde ich nicht mehr darauf achten: Seien Sie vorsichtig und vorsichtig!
Fügen Sie nun die Implementierungen der Hash-Funktion hinzu. Alle Implementierungen befinden sich in src / lib / crypto / openssl / hash_provider / hash_evp.c . Dort müssen Sie Folgendes hinzufügen:
// deps !!! #include "crypto_int.h" #include "gost_helper.h" #include <openssl/evp.h> ... static krb5_error_code hash_sha384(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_sha384(), data, num_data, output); } static krb5_error_code hash_stribog256(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_gostR3411_2012_256(), data, num_data, output); } static krb5_error_code hash_stribog512(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_gostR3411_2012_512(), data, num_data, output); } // /* -- -- -- -- */ const struct krb5_hash_provider krb5int_hash_sha384 = { "SHA-384", 48, 128, hash_sha384 }; const struct krb5_hash_provider krb5int_hash_stribog256 = { "GOSTR34.11-2012-256", 32, 64, hash_stribog256 }; const struct krb5_hash_provider krb5int_hash_stribog512 = { "GOSTR34.11-2012-512", 64, 64, hash_stribog512 };
Jetzt müssen wir diese Kontexte in der gesamten Bibliothek deklarieren. Erstellen Sie dazu ihre Beschreibung in der Datei src / lib / crypto / krb / crypto_int.h .
// , , , krb5_hash_provider - : ... struct krb5_hash_provider { char hash_name[32]; // 8 size_t hashsize, blocksize; krb5_error_code (*hash)(const krb5_crypto_iov *data, size_t num_data, krb5_data *output); }; ... extern const struct krb5_hash_provider krb5int_hash_sha384; extern const struct krb5_hash_provider krb5int_hash_stribog256; extern const struct krb5_hash_provider krb5int_hash_stribog512; ...
Wir deklarieren die Kennung des Stribog- und AES-Bundles und führen Makros ein, die wir CKSUMTYPE_STRIBOG_256_AES256 , CKSUMTYPE_STRIBOG_512_AES256 , ENCTYPE_AES256_CTS_STRIBOG_256 , ENCTYPE_AES256_ nennen . Sie müssen in der Header-Dateivorlage src / include / krb5 / krb5.hin deklariert werden . Es wird ungefähr so aussehen:
#define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018 /**< RFC 4757 */ #define ENCTYPE_CAMELLIA128_CTS_CMAC 0x0019 /**< RFC 6803 */ #define ENCTYPE_CAMELLIA256_CTS_CMAC 0x001a /**< RFC 6803 */ #define ENCTYPE_AES256_CTS_STRIBOG_256 0x001b /**< NO RFC */ #define ENCTYPE_AES256_CTS_STRIBOG_512 0x001c /**< NO RFC */ #define ENCTYPE_UNKNOWN 0x01ff ... #define CKSUMTYPE_CMAC_CAMELLIA256 0x0012 /**< RFC 6803 */ #define CKSUMTYPE_MD5_HMAC_ARCFOUR -137 /* Microsoft netlogon */ #define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /**< RFC 4757 */ #define CKSUMTYPE_STRIBOG_256_AES256 -139 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_512_AES256 -140 /**< NO RFC */
Jetzt müssen Sie zwei Bündel der Hashing- und Verschlüsselungsfunktionen sowie der Verschlüsselungs- und Hashing-Funktionen hinzufügen. Warum zwei, wenn sie gleichwertig sind, fragen Sie? Antwort: Ich weiß es nicht, oder ist es eine historische Krücke oder ein Weg zur Optimierung. Fügen wir dennoch den erforderlichen Dateien neue Strukturen hinzu:
// src/lib/crypto/krb/cksumtypes.c /* -- -- -- -- -- -- -- " " -- -- -- */ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = { ... { CKSUMTYPE_STRIBOG_256_AES256, "stribog-256-aes256", { 0 }, "STRIBOG256 AES256 key", &krb5int_enc_aes256, &krb5int_hash_stribog256, krb5int_etm_checksum, NULL, 64, 32, 0 }, { CKSUMTYPE_STRIBOG_512_AES256, "stribog-512-aes256", { 0 }, "STRIBOG512 AES256 key", &krb5int_enc_aes256, &krb5int_hash_stribog512, krb5int_etm_checksum, NULL, 64, 64, 0 }, }; // src/lib/crypto/krb/etypes.c : /* -- -- -- -- -- -- -- -- , -- , -- , -- -- -- -- */ const struct krb5_keytypes krb5int_enctypes_list[] = { ... { ENCTYPE_AES256_CTS_STRIBOG_256, "aes256-cts-stribog-256", { "aes256-stribog256" }, "AES-256 CTS mode with 256-bit stribog", &krb5int_enc_aes256, &krb5int_hash_stribog256, 16, krb5int_aes2_crypto_length, krb5int_etm_encrypt, krb5int_etm_decrypt, krb5int_aes2_string_to_key, k5_rand2key_direct, krb5int_aes2_prf, CKSUMTYPE_STRIBOG_256_AES256, 0 /*flags*/, 256 }, { ENCTYPE_AES256_CTS_STRIBOG_512, "aes256-cts-stribog-512", { "aes256-stribog512" }, "AES-256 CTS mode with 512-bit stribog", &krb5int_enc_aes256, &krb5int_hash_stribog512, 16, krb5int_aes2_crypto_length, krb5int_etm_encrypt, krb5int_etm_decrypt, krb5int_aes2_string_to_key, k5_rand2key_direct, krb5int_aes2_prf, CKSUMTYPE_STRIBOG_512_AES256, 0 /*flags*/, 256 }, };
Es scheint, dass alle, aber nein! Dann gibt es Probleme, die nur während des Debugging-Prozesses sichtbar werden. Einige davon könnten vermieden werden, indem beispielsweise andere Zeiger auf Funktionen in den obigen Strukturen angegeben werden. Wir werden jedoch komplizierter zeigen, was Sie möglicherweise noch auf dem Weg beheben müssen. Ich habe all diese Probleme nur mit dem Debugger kennengelernt:
// src/lib/crypto/openssl/hmac.c map_digest -- - . . : #include "crypto_int.h" #include "gost_helper.h" #include <openssl/hmac.h> #include <openssl/evp.h> static const EVP_MD * map_digest(const struct krb5_hash_provider *hash) { if (!strncmp(hash->hash_name, "SHA1",4)) return EVP_sha1(); ... else if (!strncmp(hash->hash_name, "GOSTR34.11-2012-256", 19)) return EVP_gostR3411_2012_256(); else if (!strncmp(hash->hash_name, "GOSTR34.11-2012-512", 19)) return EVP_gostR3411_2012_512(); else return NULL; } // src/lib/crypto/openssl/pbkdf2.c krb5int_pbkdf2_hmac, : krb5_error_code krb5int_pbkdf2_hmac(const struct krb5_hash_provider *hash, const krb5_data *out, unsigned long count, const krb5_data *pass, const krb5_data *salt) { const EVP_MD *md = NULL; /* Get the message digest handle corresponding to the hash. */ if (hash == &krb5int_hash_sha1) md = EVP_sha1(); ... else if (hash == &krb5int_hash_stribog256) md = EVP_gostR3411_2012_256(); else if (hash == &krb5int_hash_stribog512) md = EVP_gostR3411_2012_512(); ... return 0; } // src/lib/krb5/krb/init_ctx.c , : static krb5_enctype default_enctype_list[] = { ... ENCTYPE_AES256_CTS_STRIBOG_256, ENCTYPE_AES256_CTS_STRIBOG_512, 0 };
Nach all diesen Änderungen können Sie die Funktionsweise des Algorithmus überprüfen. Wir werden alles sammeln, was wir getan haben.
autoconf ./configure --with-crypto-impl=openssl
Beginnen wir jetzt mit der Überprüfung. Dazu setzen wir die erzwungene Verwendung der von uns implementierten Algorithmen in die Kerberos-Konfigurationsdateien ein. Gehen Sie wie folgt vor:
Stoppen Sie krb5kdc:
service krb5-kdc stop
Wir werden die Konfigurationsdatei kdc.conf reparieren (ich habe diese /usr/local/var/krb5kdc/kdc.conf). Stellen Sie erzwungenes Hashing mit dem neu eingeführten Algorithmus ein:
[realms] AKTIV-TEST.RU = { master_key_type = aes256-stribog512 supported_enctypes = aes256-stribog512:normal default_tgs_enctypes = aes256-stribog512 default_tkt_enctypes = aes256-stribog512 permitted_enctypes = aes256-stribog512 }
Ähnliche Änderungen in der Konfigurationsdatei des gesamten krb5.conf-Protokolls (ich habe es unter /etc/krb5.conf):
[libdefaults] supported_enctypes = aes256-stribog512:normal default_tgs_enctypes = aes256-stribog512 default_tkt_enctypes = aes256-stribog512 permitted_enctypes = aes256-stribog512 # 256
Führen Sie als nächstes krb5kdc seit aus Wenn sich master_key ändert, müssen Sie möglicherweise die Principals-Datenbank erneut mit krb5_newrealm erstellen.
Danach erstellen wir alle erforderlichen Principals und Sie können mit der Arbeit beginnen. Versuchen Sie, sich mit kinit zu authentifizieren.
Wir werden überprüfen, ob das Hashing gemäß dem angegebenen Algorithmus erfolgt.
mit klist -e.
Wenn der Dienst nicht gestartet wird, kann er mit src / kdc / krb5kdc unter dem Stammverzeichnis gestartet werden . Wenn alles begann, lief es reibungslos - Glückwunsch! Ansonsten biete ich leider nicht für alle Probleme ein Allheilmittel an, sondern nur eine "kleine" Anweisung, die die grundlegenden Schritte enthält, die Sie ausführen müssen, um den neuen Algorithmus in Kerberos zu implementieren. Und wenn für Sie nichts klappt - holen Sie sich gdb und sehen Sie, wo was schief geht. Ich kann Ihnen nur einige Tipps geben:
- Sie können ein Projekt im Debug-Modus erstellen, wenn Sie es an ./configure CFLAGS = "-g -O0" übergeben.
- krb5kdc kann im Hintergrund mit dem Flag -n gestartet werden.
- Ich hoffe, es kommt nicht dazu (obwohl ich immer noch die Implementierung asymmetrischer Algorithmen entwickelt habe) - Sie benötigen möglicherweise openssl-Debugging-Symbole - installieren Sie sie entweder aus dem Repository oder installieren Sie openssl aus dem Quellcode mit Debugging-Symbolen.
- das gleiche gilt für gost motor.
Die Idee dieser Tipps sollte ausreichen, damit Sie keine Zeit damit verschwenden müssen, nach dem „Unbekannten“ zu suchen.
Implementierung des Verschlüsselungsalgorithmus
In diesem Abschnitt werde ich zeigen, wie Sie Ihren eigenen Datenverschlüsselungsalgorithmus in Kerberos hinzufügen können, und wir werden versuchen, eine Reihe von Magma und Stribog zu erstellen, die im letzten Abschnitt hinzugefügt wurden. Hier gehe ich bereits davon aus, dass die kleine Bibliothek gost_helper bereits im letzten Abschnitt hinzugefügt wurde. Nun, strecken Sie Ihre Finger und fahren Sie fort:
Zunächst beschreiben wir den Algorithmus in unserer Bibliothek libk5crypto, indem wir ihn in der Header-Datei src / lib / crypto / krb / crypto_int.h beschreiben .
... extern const struct krb5_enc_provider krb5int_enc_camellia256; extern const struct krb5_enc_provider krb5int_enc_gost89; ...
Fügen Sie im Verzeichnis src / lib / crypto / openssl / enc_provider den Quellcode gost.c hinzu, der die Implementierung aller erforderlichen Algorithmen enthält (ich habe den Quellcode für den des-Algorithmus als Basis verwendet). Es ist wichtig zu beachten, dass wir nur den cbc-Verschlüsselungsmodus implementieren, sodass Sie zum Selbsttest jeden anderen Verschlüsselungsmodus verwenden und hinzufügen können:
#include "crypto_int.h" #include "gost_helper.h" #include <openssl/evp.h> #define BLOCK_SIZE 8 static krb5_error_code krb5int_gost_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { int ret, olen = BLOCK_SIZE; unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE]; struct iov_cursor cursor; EVP_CIPHER_CTX *ctx; // , krb5int_gost_encrypt, : krb5int_init_gost(); ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; ret = EVP_EncryptInit_ex(ctx, EVP_get_cipherbynid(NID_gost89_cbc), NULL, key->keyblock.contents, (ivec) ? (unsigned char*)ivec->data : NULL); if (!ret) { EVP_CIPHER_CTX_free(ctx); return KRB5_CRYPTO_INTERNAL; } EVP_CIPHER_CTX_set_padding(ctx,0); k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE); while (k5_iov_cursor_get(&cursor, iblock)) { ret = EVP_EncryptUpdate(ctx, oblock, &olen, iblock, BLOCK_SIZE); if (!ret) break; k5_iov_cursor_put(&cursor, oblock); } if (ivec != NULL) memcpy(ivec->data, oblock, BLOCK_SIZE); EVP_CIPHER_CTX_free(ctx); zap(iblock, sizeof(iblock)); zap(oblock, sizeof(oblock)); if (ret != 1) return KRB5_CRYPTO_INTERNAL; return 0; } static krb5_error_code krb5int_gost_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { int ret, olen = BLOCK_SIZE; unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE]; struct iov_cursor cursor; EVP_CIPHER_CTX *ctx; krb5int_init_gost(); ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; ret = EVP_DecryptInit_ex(ctx, EVP_get_cipherbynid(NID_gost89_cbc), NULL, key->keyblock.contents, (ivec) ? (unsigned char*)ivec->data : NULL); if (!ret) { EVP_CIPHER_CTX_free(ctx); return KRB5_CRYPTO_INTERNAL; } EVP_CIPHER_CTX_set_padding(ctx,0); k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE); while (k5_iov_cursor_get(&cursor, iblock)) { ret = EVP_DecryptUpdate(ctx, oblock, &olen, (unsigned char *)iblock, BLOCK_SIZE); if (!ret) break; k5_iov_cursor_put(&cursor, oblock); } if (ivec != NULL) memcpy(ivec->data, iblock, BLOCK_SIZE); EVP_CIPHER_CTX_free(ctx); zap(iblock, sizeof(iblock)); zap(oblock, sizeof(oblock)); if (ret != 1) return KRB5_CRYPTO_INTERNAL; return 0; } static krb5_error_code krb5int_gost_init_state (const krb5_keyblock *key, krb5_keyusage usage, krb5_data *state) { state->length = 8; state->data = (void *) malloc(8); if (state->data == NULL) return ENOMEM; memset(state->data, 0, state->length); return 0; } static void krb5int_gost_free_state(krb5_data *state) { free(state->data); *state = empty_data(); } /* -- , -- - -- -- -- -- cbc-mac checksum, , .. -- -- */ const struct krb5_enc_provider krb5int_enc_gost89 = { BLOCK_SIZE, 32, 32, krb5int_gost_encrypt, krb5int_gost_decrypt, NULL, krb5int_gost_init_state, krb5int_gost_free_state };
In der Vorlage src / lib / crypto / openssl / enc_provider / Makefile.in geben wir an, dass eine neue Quelle angezeigt wurde:
STLIBOBJS= \ des.o \ ... gost.o OBJS= \ $(OUTPRE)des.$(OBJEXT) \ ... $(OUTPRE)gost$(OBJEXT) SRCS= \ $(srcdir)/des.c \ ... $(srcdir)/gost.c
Vergessen Sie nicht, Abhängigkeiten in src / lib / crypto / openssl / enc_provider / deps anzugeben :
gost.so gost.po $(OUTPRE)gost.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \ $(srcdir)/../crypto_mod.h $(top_srcdir)/include/k5-buf.h \ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ $(top_srcdir)/include/socket-utils.h $(srcdir)/../gost_helper.h gost.c
Fügen Sie die Bundle- IDs zu src / include / krb5 / krb5.hin hinzu :
... #define ENCTYPE_AES256_CTS_STRIBOG_256 0x001b /**< NO RFC */ #define ENCTYPE_AES256_CTS_STRIBOG_512 0x001c /**< NO RFC */ #define ENCTYPE_GOST89_CBC_STRIBOG_256 0x001d /**< SOME GOST */ #define ENCTYPE_GOST89_CBC_STRIBOG_512 0x001e /**< SOME GOST */ #define ENCTYPE_UNKNOWN 0x01ff ... #define CKSUMTYPE_STRIBOG_256_AES256 -139 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_512_AES256 -140 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_256_GOST89 -141 /**< SOME GOST */ #define CKSUMTYPE_STRIBOG_512_GOST89 -142 /**< SOME GOST */
Beschreiben wir die Struktur der Hash- und Verschlüsselungsfunktionspakete wie im letzten Abschnitt:
// src/lib/crypto/krb/cksumtypes.c const struct krb5_cksumtypes krb5int_cksumtypes_list[] = { ... { CKSUMTYPE_STRIBOG_256_GOST89, "stribog-256-gost89", { 0 }, "STRIBOG256 GOST89 key", &krb5int_enc_gost89, &krb5int_hash_stribog256, krb5int_dk_checksum, NULL, 64, 32, 0 }, { CKSUMTYPE_STRIBOG_512_GOST89, "stribog-512-gost89", { 0 }, "STRIBOG512 GOST89 key", &krb5int_enc_gost89, &krb5int_hash_stribog512, krb5int_dk_checksum, NULL, 64, 64, 0 }, }; // src/lib/crypto/krb/etypes.c // , , , aes const struct krb5_keytypes krb5int_enctypes_list[] = { ... { ENCTYPE_GOST89_CBC_STRIBOG_256, "gost89-cbc-stribog-256", { "gost89-stribog256" }, "GOST 28147-89 CBC mode with 256-bit stribog", &krb5int_enc_gost89, &krb5int_hash_stribog256, 16, krb5int_dk_crypto_length, krb5int_dk_encrypt, krb5int_dk_decrypt, krb5int_dk_string_to_key, k5_rand2key_direct, krb5int_dk_prf, CKSUMTYPE_STRIBOG_256_GOST89, 0 /*flags*/, 256 }, { ENCTYPE_GOST89_CBC_STRIBOG_512, "gost89-cbc-stribog-512", { "gost89-stribog512" }, "GOST 28147-89 CBC mode with 512-bit stribog", &krb5int_enc_gost89, &krb5int_hash_stribog512, 16, krb5int_dk_crypto_length, krb5int_dk_encrypt, krb5int_dk_decrypt, krb5int_dk_string_to_key, k5_rand2key_direct, krb5int_dk_prf, CKSUMTYPE_STRIBOG_512_GOST89, 0 /*flags*/, 256 }, };
Fügen Sie der Liste der Standardverschlüsselungsmodi in der Datei src / lib / krb5 / krb / init_ctx.c Folgendes hinzu :
static krb5_enctype default_enctype_list[] = { ... ENCTYPE_AES256_CTS_STRIBOG_256, ENCTYPE_AES256_CTS_STRIBOG_512, ENCTYPE_GOST89_CBC_STRIBOG_256, ENCTYPE_GOST89_CBC_STRIBOG_512, 0 };
Nach diesen Manipulationen können Sie versuchen, den neu eingeführten Algorithmus zu testen. Das Testen erfolgt auf die gleiche Weise wie im letzten Abschnitt . Der Name des Bundles kann in Form eines Alias (z. B. gost89-stribog512) oder unter Verwendung des Namens des Algorithmus selbst (z. B. gost89-cbc-stribog-512) verwendet werden. Ich hoffe, dass alles funktioniert, sonst vergiss nicht, was ich vorher gesagt habe .
Hinzufügen eines Algorithmus für digitale Signaturen
Hurra! Wir fahren mit dem letzten Abschnitt dieses Artikels fort und versuchen, unseren eigenen Algorithmus für die elektronische Signatur hinzuzufügen. Haben Sie keine Angst, das Hinzufügen ist einfacher als alles andere. Beginnen wir also so schnell wie möglich ... Obwohl nein, warten Sie eine kleine Bemerkung, um zu beginnen.
Asymmetrische Verschlüsselung ist eine ziemlich schwere Sache. – : , - . ...
, . , , . . . . , . , . , , — . .
- . , , . : . , , , , , .
openssl ( )
, -, openssl rtengine. GOST, , .
SDK rutoken sdk/openssl/rtengine/bin/ engine.
librtpkcs11ecp.so. von hier
master OpenSC 8cf1e6f
, openssl.cnf:
engine .
, KDC
kerberos . , .
, , , KDC:
openssl genpkey -engine gost -algorithm gost2012_256 -pkeyopt paramset:B -out CA_key.pem
kdc, , :
[kdcdefaults] ... pkinit_identity = FILE:/var/lib/krb5kdc/KDC.pem,/var/lib/krb5kdc/KDC_key.pem pkinit_anchors = FILE:/var/lib/krb5kdc/CA_cert.pem
[libdefaults]
spake_preauth_groups = edwards25519
3. : ```bash sudo kadmin.local kadmin.local$: modprinc +requires_preauth user
. , , : :
, KDC:
openssl genpkey -engine gost -algorithm gost2012_256 -pkeyopt paramset:B -out client_key.pem
:
pkcs11-tool --module /path/to/module/librtpkcs11ecp.so --keypairgen --key-type GOSTR3410-2012-256:B -l --id 45
:
REALM=AKTIV-TEST.RU; export REALM
: , – :
sudo cp ./client_key.pem client.pem /etc/krb5
( /etc/krb5.conf):
[libdefaults] ... pkinit_anchors = FILE:/var/lib/krb5kdc/CA_cert.pem
, . ! .
, – - 2 ! src/plugins/preauth/pkinit/pkcs11.h src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
pkcs11.h . – , , . ( ). sdk/pkcs11/include/rtpkcs11t.h . :
... #define CKK_TWOFISH (0x21) #define CKK_GOSTR3410 (0x30) #define CKK_GOSTR3411 (0x31) #define CKK_GOST28147 (0x32) #define CKK_VENDOR_DEFINED (1UL << 31) // A mask for new GOST algorithms. // For details visit https://tc26.ru/standarts/perevody/guidelines-the-pkcs-11-extensions-for-implementing-the-gost-r-34-10-2012-and-gost-r-34-11-2012-russian-standards-.html #define NSSCK_VENDOR_PKCS11_RU_TEAM (CKK_VENDOR_DEFINED | 0x54321000) #define CK_VENDOR_PKCS11_RU_TEAM_TK26 NSSCK_VENDOR_PKCS11_RU_TEAM #define CKK_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x003) ... #define CKM_AES_MAC_GENERAL (0x1084) #define CKM_AES_CBC_PAD (0x1085) #define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200UL) #define CKM_GOSTR3410 (0x1201UL) #define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202UL) #define CKM_GOSTR3410_KEY_WRAP (0x1203UL) #define CKM_GOSTR3410_DERIVE (0x1204UL) #define CKM_GOSTR3410_512_KEY_PAIR_GEN (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x005) #define CKM_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x006) #define CKM_GOSTR3410_12_DERIVE (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x007) #define CKM_GOSTR3410_WITH_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x008) #define CKM_GOSTR3410_WITH_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x009) #define CKM_GOSTR3411 (0x1210UL) #define CKM_GOSTR3411_HMAC (0x1211UL) #define CKM_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x012) #define CKM_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x013) #define CKM_GOSTR3411_12_256_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x014) #define CKM_GOSTR3411_12_512_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x015) #define CKM_GOST28147_KEY_GEN (0x1220UL) #define CKM_GOST28147_ECB (0x1221UL) #define CKM_GOST28147 (0x1222UL) #define CKM_GOST28147_MAC (0x1223UL) #define CKM_GOST28147_KEY_WRAP (0x1224UL)
, .
pkinit_crypto_openssl.c , , . get_key, .. - :
#include <dirent.h> #include <arpa/inet.h> #include <openssl/engine.h> static ENGINE *eng = NULL; krb5int_init_engines() { if (eng) return; OPENSSL_add_all_algorithms_conf(); ERR_load_crypto_strings(); if (!(eng = ENGINE_by_id("rtengine"))) { printf("Engine rtengine doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); if (!(eng = ENGINE_by_id("gost"))) { printf("Engine gost doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); } ... get_key(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, char *filename, const char *fsname, EVP_PKEY **retkey, const char *password) { ... krb5_error_code retval; krb5int_init_engines(); ... } ... int pkinit_openssl_init() { /* Initialize OpenSSL. */ ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); krb5int_init_engines(); return 0; }
. – RSA , sha1. , . , , . , .. RSA :
// krb5_error_code pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx, CK_ATTRIBUTE_TYPE usage, CK_OBJECT_HANDLE *objp) { ... true_false = TRUE; attrs[nattrs].type = usage; attrs[nattrs].pValue = &true_false; attrs[nattrs].ulValueLen = sizeof true_false; nattrs++; #endif // keytype = CKK_RSA; // attrs[nattrs].type = CKA_KEY_TYPE; // attrs[nattrs].pValue = &keytype; // attrs[nattrs].ulValueLen = sizeof keytype; // nattrs++; ... } // : static int ckk_key_to_nid(CK_KEY_TYPE type) { switch(type){ case CKK_GOSTR3410: return NID_id_GostR3410_2012_256; case CKK_GOSTR3410_512: return NID_id_GostR3410_2012_512; default: return NID_rsa; } } // , , : static int pkinit_get_pkey_type(krb5_context context, pkinit_identity_crypto_context id_cryptoctx) { CK_OBJECT_HANDLE obj; CK_ATTRIBUTE attrs[1]; CK_KEY_TYPE key_type; int r; // : if (pkinit_open_session(context, id_cryptoctx)) { pkiDebug("can't open pkcs11 session\n"); return NID_rsa; } // : if (pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj)) { return NID_rsa; } // : attrs[0].type = CKA_KEY_TYPE; attrs[0].pValue = &key_type; attrs[0].ulValueLen = sizeof (key_type); if ((r = id_cryptoctx->p11->C_GetAttributeValue(id_cryptoctx->session, obj, attrs, 1)) != CKR_OK) { pkiDebug("C_GetAttributeValue: %s\n Used RSA\n", pkinit_pkcs11_code_to_text(r)); return NID_rsa; } // : return ckk_key_to_nid(key_type); } // , , : static int pkey_to_digest_nid(const EVP_PKEY* const pkey) { switch (EVP_PKEY_id(pkey)) { case NID_id_GostR3410_2012_256: return NID_id_GostR3411_2012_256; case NID_id_GostR3410_2012_512: return NID_id_GostR3411_2012_512; case NID_id_GostR3410_2001: return NID_id_GostR3411_2012_256; default: return NID_sha1; } } // , : static int get_digest_nid(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; // ( ), NID , if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return NID_id_GostR3411_2012_256; case NID_id_GostR3410_2012_512: return NID_id_GostR3411_2012_512; case NID_id_GostR3410_2001: return NID_id_GostR3411_2012_256; default: return NID_sha1; } } // , : static int get_alg_nid(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return NID_id_tc26_signwithdigest_gost3410_2012_256; case NID_id_GostR3410_2012_512: return NID_id_tc26_signwithdigest_gost3410_2012_512; case NID_id_GostR3410_2001: return NID_id_tc26_signwithdigest_gost3410_2012_256; default: return NID_sha1WithRSAEncryption; } } // : static CK_MECHANISM_TYPE get_mech_type(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return CKM_GOSTR3410_WITH_GOSTR3411_12_256; case NID_id_GostR3410_2012_512: return CKM_GOSTR3410_WITH_GOSTR3411_12_512; case NID_id_GostR3410_2001: return CKM_GOSTR3410_WITH_GOSTR3411_12_256; default: return CKM_RSA_PKCS; } }
cms_signeddata_create create_signature :
krb5_error_code cms_signeddata_create(krb5_context context, pkinit_plg_crypto_context plg_cryptoctx, pkinit_req_crypto_context req_cryptoctx, pkinit_identity_crypto_context id_cryptoctx, int cms_msg_type, int include_certchain, unsigned char *data, unsigned int data_len, unsigned char **signed_data, unsigned int *signed_data_len) { ... /* Set digest algs */ p7si->digest_alg->algorithm = OBJ_nid2obj( get_digest_nid(context, id_cryptoctx)); ... p7si->digest_enc_alg->algorithm = OBJ_nid2obj(get_alg_nid(context, id_cryptoctx)); ... EVP_DigestInit_ex(ctx, EVP_get_digestbynid(get_digest_nid(context, id_cryptoctx)), NULL); ... alen = (unsigned int )ASN1_item_i2d((ASN1_VALUE *) sk, &abuf, ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); ... // , ( ): if (id_cryptoctx->pkcs11_method == 1 && get_digest_nid(context, id_cryptoctx) == NID_sha1) { } static krb5_error_code create_signature(unsigned char **sig, unsigned int *sig_len, unsigned char *data, unsigned int data_len, EVP_PKEY *pkey) { ... EVP_SignInit(ctx, EVP_get_digestbynid(pkey_to_digest_nid(pkey))); ... } // : static krb5_error_code pkinit_sign_data_pkcs11(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, unsigned char *data, unsigned int data_len, unsigned char **sig, unsigned int *sig_len) { ... mech.mechanism = get_mech_type(context, id_cryptoctx); mech.pParameter = NULL; mech.ulParameterLen = 0; ... }
, ( , , ):
sudo kinit user
user, , .
, .