Présentation

Le protocole Kerberos 5 est désormais activement utilisé pour l'authentification. Une caractéristique de ce protocole est qu'il effectue une authentification basée sur quatre piliers:
- Cryptage symétrique;
- Hachage
- EDS;
- Troisième partie de confiance.
À partir de la cinquième version, il est désormais possible d'utiliser le cryptage asymétrique (pour la signature électronique). Il n'est pas logique de s'attarder sur le fonctionnement du protocole Kerberos, car la description de l'algorithme peut être trouvée ici .
Malheureusement, le nombre d'algorithmes de chiffrement, de hachage et de signature numérique que ce protocole utilise n'est pas aussi important que je le voudrais, donc dans cet article, je veux montrer comment ajouter facile et simple propres algorithmes pour la mise en œuvre de ce protocole par le MIT . Nous ajouterons nos algorithmes nationaux: GOST 28147-89 (alias Magma), GOST R 34.11-2012 (alias Stribog) et GOST R 34.10-2012 (j'aimerais aussi avoir aka pour cela, mais je ne sais pas :(). Prêt une solution pour ces algorithmes peut être trouvée dans mon référentiel . Côté client, nous utiliserons les implémentations matérielles des algorithmes GOST dans Rutoken EDS 2.0 et leurs implémentations logicielles dans le moteur GOST pour openssl. Mais l'option la plus sûre pour stocker les clés est quand elles sont générées directement sur Rutoken et jamais ne quitte pas sa mémoire lors d'opérations cryptographiques Pour cette option, rtengine est requis.
Avant de commencer à mettre en œuvre les algorithmes, nous décrivons les principaux endroits où des modifications seront apportées. Le répertoire src / lib / crypto / contient les implémentations de tous les algorithmes responsables de la cryptographie et du hachage symétriques. Il a 2 implémentations de ces algorithmes cryptographiques: builtin et openssl. Afin de gagner du temps et de l'espace, nous ajouterons bien sûr l'implémentation d'algorithmes utilisant openssl, dans lesquels ils existent déjà (enfin, ou presque, mais plus à ce sujet plus tard). Pour ajouter des algorithmes asymétriques, vous devrez modifier le plugin src / plugins / preauth / pkinit
Si vous n'avez pas encore configuré Kerberos, les instructions pour sa configuration et son fonctionnement initiaux peuvent être trouvées ici . De plus, l'auteur suppose que vous travaillez avec le domaine AKTIV-TEST.RU
Ajout d'algorithmes de hachage et de chiffrement symétrique
Comme cela a été annoncé précédemment, nous n'écrirons pas les algorithmes de chiffrement et de hachage à partir de zéro, mais utiliserons une implémentation prête à l'emploi de ces algorithmes dans openssl. Openssl ne prend pas directement en charge la mise en œuvre d'algorithmes nationaux, mais il est mobile à cet égard et vous permet d'ajouter de nouveaux algorithmes à l'aide du mécanisme GOST du moteur pour travailler avec des clés dans le système de fichiers et stockées sur le jeton - rtengine.
Une petite introduction au moteur du moteur openssl et la connexion du moteur GOST
Le moteur dans openssl est une petite bibliothèque dynamique qui ouvre les charges dans runtime à la demande. Chacune de ces bibliothèques doit contenir certains symboles (fonctions) pour charger les algorithmes nécessaires. Dans cet article, nous utiliserons le moteur gost, qui contient tous les algorithmes cryptographiques nationaux nécessaires.
L'installation est d'une simplicité déconcertante, par exemple, et se déroule comme suit:
Téléchargez l' implémentation de ce moteur depuis le référentiel .
construire une bibliothèque avec elle (mkdir build && cd build && cmake ... && make):
mkdir build cd build cmake .. make
Dans le répertoire bin (QUI APPARAÎTRA DANS LE CATALOGUE ROOT DU PROJET !!!), il y aura une bibliothèque dynamique gost.so - c'est notre Engin. Il devra être déplacé vers le répertoire où sont stockés les moteurs openssl. Découvrez l'emplacement de ce répertoire en utilisant:
openssl version -a | grep ENGINESDIR
Cela dépend de ce dernier - vous devez dire à openssl où se trouve le moteur donné et comment il s'appelle. Vous pouvez le faire en modifiant le fichier de configuration openssl.cnf. L'emplacement peut être trouvé en utilisant:
openssl version -a | grep OPENSSLDIR
À la fin de ce fichier, vous devrez ajouter le contenu suivant:
Après cela, ce moteur devrait apparaître dans openssl. Vous pouvez vérifier ses performances en forçant, par exemple, à générer une clé privée dans un fichier selon GOST R 34.10-2012:
openssl genpkey -engine gost -algorithm gost2012_512 -pkeyopt paramset:A -out client_key.pem
L'indicateur -engine indique simplement quel moteur doit être chargé avant de commencer le travail afin que l'algorithme de génération de clé pour GOST R 34.10-2012 devienne visible.
Implémentation de l'algorithme de hachage
Commençons par le plus simple - avec l'implémentation de l'algorithme Stribog. Kerberos a une forte connexion entre les algorithmes de hachage et de chiffrement, c'est-à-dire que vous ne pouvez pas simplement choisir un algorithme de chiffrement, et pour en hacher un autre, vous devrez intégrer l'algorithme de hachage et de chiffrement. Je ne connais pas la raison de cela, mais comme il existe de telles règles - essayons de créer une combinaison de l'algorithme Stribog et d'AES.
Parce que nous avons besoin de confiance dans la connexion à différents endroits de notre programme, créons d'abord une petite bibliothèque gost_helper qui contiendra la fonction d'initialisation du moteur dans openssl, ainsi que quelques fonctions qui renvoient les contextes de certains algorithmes de hachage pour plus de commodité - cela nous aidera à l'avenir. Nous nommons cette bibliothèque gost_helper et créons un en-tête et un fichier source appropriés dans le répertoire 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); }
Après avoir ajouté la bibliothèque auxiliaire, vous devrez déclarer son existence dans le Makefile et écrire ses dépendances de fichier. Pour ce faire, ajoutez les éléments suivants:
Il convient de noter qu'à l'avenir, lors de la connexion de cette bibliothèque, nous devrons ajouter des dépendances de certains fichiers sur l'en-tête de cette bibliothèque. Cela se fait très simplement - l'objectif est trouvé, où vous devez ajouter la dépendance dans le fichier deps et la dépendance à rel / path / to / gost_helper.h est enregistrée . Par exemple, dans src / lib / crypto / openssl / hash_provider / deps, vous devez ajouter les éléments suivants:
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
Afin de gagner de la place dans l'article et d'étirer votre cerveau, je n'y ferai plus attention: soyez prudent et prudent!
Ajoutez maintenant les implémentations de fonctions de hachage, toutes leurs implémentations sont dans src / lib / crypto / openssl / hash_provider / hash_evp.c . Là, vous devrez ajouter les éléments suivants:
// 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 };
Maintenant, nous devons déclarer ces contextes dans toute la bibliothèque. Pour ce faire, créez leur description dans le fichier 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; ...
Nous déclarerons l'identifiant du bundle Stribog et AES, en introduisant les macros que nous appellerons CKSUMTYPE_STRIBOG_256_AES256 , CKSUMTYPE_STRIBOG_512_AES256 , ENCTYPE_AES256_CTS_STRIBOG_256 , ENCTYPE_AES256_CTS_STRIBOG . Ils doivent être déclarés dans le modèle de fichier d'en-tête src / include / krb5 / krb5.hin . Cela ressemblera à ceci:
#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 */
Vous devez maintenant ajouter deux ensembles de fonctions de hachage et de chiffrement et de fonctions de chiffrement et de hachage. Pourquoi deux, s'ils sont équivalents, demandez-vous? Réponse: Je ne sais pas, ou est-ce une béquille historique ou un moyen d'optimiser. Ajoutons néanmoins de nouvelles structures aux fichiers nécessaires:
// 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 }, };
Il semblerait que tout, mais non! Ensuite, il y a des problèmes qui ne seront visibles que pendant le processus de débogage, certains d'entre eux pourraient être évités en indiquant, par exemple, d'autres pointeurs vers des fonctions dans les structures ci-dessus, mais nous irons d'une manière plus compliquée pour montrer ce que vous pourriez avoir à corriger en cours de route. J'ai appris tous ces problèmes uniquement en utilisant le débogueur:
// 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 };
Après toutes ces modifications, vous pouvez vérifier le fonctionnement de l'algorithme. Nous collecterons tout ce que nous avons fait.
autoconf ./configure --with-crypto-impl=openssl
Commençons maintenant à vérifier. Pour ce faire, plaçons l'utilisation forcée des algorithmes que nous avons implémentés dans les fichiers de configuration Kerberos. Procédez comme suit:
Arrêtez krb5kdc:
service krb5-kdc stop
Nous allons corriger le fichier de configuration kdc.conf (j'ai pour moi /usr/local/var/krb5kdc/kdc.conf). Définissez le hachage forcé à l'aide du nouvel algorithme introduit:
[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 }
Modifications similaires dans le fichier de configuration de l'ensemble du protocole krb5.conf (je l'ai sur /etc/krb5.conf):
[libdefaults] supported_enctypes = aes256-stribog512:normal default_tgs_enctypes = aes256-stribog512 default_tkt_enctypes = aes256-stribog512 permitted_enctypes = aes256-stribog512 # 256
Ensuite, exécutez krb5kdc depuis Si master_key change, vous devrez peut-être recréer la base de données des principaux à l'aide de krb5_newrealm.
Après cela, nous créons tous les principes nécessaires et vous pouvez commencer à travailler. Essayez de vous authentifier avec kinit.
Nous vérifierons que le hachage se produit selon l'algorithme spécifié.
en utilisant klist -e.
Si le service ne démarre pas, il peut être démarré sous la racine à l'aide de src / kdc / krb5kdc . Si tout a commencé, tout s'est bien passé - félicitations! Sinon - hélas, je n'offre pas de panacée pour tous les problèmes, mais seulement une "petite" instruction contenant les étapes de base que vous devrez suivre pour implémenter le nouvel algorithme dans Kerberos. Et si rien ne fonctionne pour vous, choisissez gdb et voyez où se passe le problème. Je ne peux que vous donner quelques conseils:
- vous pouvez créer un projet en mode débogage si vous le transmettez à ./configure CFLAGS = "-g -O0";
- krb5kdc peut être lancé en arrière-plan à l'aide de l'option -n;
- J'espère que cela n'arrivera pas à cela (bien que j'aie toujours trouvé l'implémentation d'algorithmes asymétriques) - vous devrez peut-être des symboles de débogage openssl - installez-les à partir du référentiel ou installez openssl à partir de la source avec des symboles de débogage;
- il en va de même pour le moteur Gost.
L'idée de cet ensemble de conseils devrait vous suffire pour vous éviter de perdre du temps à chercher «l'inconnu».
Implémentation de l'algorithme de chiffrement
Dans cette section, je montrerai comment vous pouvez ajouter votre propre algorithme de chiffrement de données dans Kerberos, et nous essaierons de créer un tas de Magma et Stribog, ajoutés dans la dernière section. Ici, je suppose déjà que la petite bibliothèque gost_helper a déjà été ajoutée dans la dernière section. Eh bien, étirez vos doigts et continuez:
Tout d'abord, nous décrivons l'algorithme dans notre bibliothèque libk5crypto en les décrivant dans le fichier d'en-tête src / lib / crypto / krb / crypto_int.h .
... extern const struct krb5_enc_provider krb5int_enc_camellia256; extern const struct krb5_enc_provider krb5int_enc_gost89; ...
Dans le répertoire src / lib / crypto / openssl / enc_provider, ajoutez le code source gost.c, qui contient l'implémentation de tous les algorithmes nécessaires (j'ai pris le code source de l'algorithme des comme base). Il est important de noter que nous n'implémentons que le mode de cryptage cbc, donc pour l'auto-test, vous pouvez prendre tout autre mode de cryptage et l'ajouter:
#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 };
Dans le modèle src / lib / crypto / openssl / enc_provider / Makefile.in, nous indiquons qu'une nouvelle source est apparue:
STLIBOBJS= \ des.o \ ... gost.o OBJS= \ $(OUTPRE)des.$(OBJEXT) \ ... $(OUTPRE)gost$(OBJEXT) SRCS= \ $(srcdir)/des.c \ ... $(srcdir)/gost.c
N'oubliez pas de spécifier les dépendances dans src / lib / crypto / openssl / enc_provider / deps :
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
Ajoutez les identificateurs de bundle à src / include / krb5 / krb5.hin :
... #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 */
Décrivons la structure des bundles de fonctions de hachage et de cryptage, comme dans la dernière section:
// 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 }, };
Ajoutez à la liste des modes de chiffrement par défaut dans le fichier src / lib / krb5 / krb / init_ctx.c :
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 };
Après ces manipulations, vous pouvez essayer de tester l'algorithme nouvellement introduit. Les tests se déroulent de la même manière que dans la dernière section . Le nom de l'ensemble peut être pris sous la forme d'un alias (par exemple, gost89-stribog512) ou en utilisant le nom de l'algorithme lui-même (par exemple, gost89-cbc-stribog-512). J'espère que tout fonctionne, sinon n'oubliez pas ce que j'ai dit plus tôt .
Ajout d'un algorithme de signature numérique
Hourra! Nous passons à la dernière section de cet article et essayons d'ajouter notre propre algorithme de signature électronique. N'ayez pas peur, l'ajouter est plus facile que toute autre chose, alors commençons le plus tôt possible ... Bien que non, attendez une petite remarque pour commencer.
Le chiffrement asymétrique est une chose assez lourde. – : , - . ...
, . , , . . . . , . , . , , — . .
- . , , . : . , , , , , .
openssl ( )
, -, openssl rtengine. GOST, , .
SDK rutoken sdk/openssl/rtengine/bin/ engine.
librtpkcs11ecp.so.
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, , .
, .