Station de travail cryptographique basée sur le conteneur PKCS # 12. Création d'une signature électronique CadES-X Long Type 1. Partie 3

image Le temps a passé et l'utilitaire, commencé en tant que visualiseur de certificats , complété par les fonctions de travail avec les jetons cryptographiques PKCS # 11 et de création de demandes (PKCS # 10) pour un certificat qualifié, a été reconstitué, comme indiqué, avec les fonctions de travail avec les conteneurs PKCS # 12.

Donc, pour travailler avec les conteneurs PKCS # 12, vous avez besoin de l'utilitaire cryptoarmpkcs:

Téléchargez, exécutez l'utilitaire cryptoarmpkcs et cliquez sur le bouton PKCS12:



La capture d'écran montre clairement ce que l'utilitaire vous permet de faire, avec le conteneur PKCS # 12 à portée de main:

  • visualiser le certificat du propriétaire, pour lequel il suffira de cliquer sur l'icône située à droite du champ "friendlyName";
  • générer l'un des trois types de signature électronique CAdes:
  • enregistrer le certificat du conteneur dans un fichier;
  • enregistrez le certificat sur le jeton;
  • enregistrez la clé privée du propriétaire sur le jeton.

Les deux dernières opérations ne sont possibles qu'avec un token connecté (la bibliothèque PKCS # 11 est sélectionnée et un token est connecté). Nous notons également que tous les jetons ne vous permettent pas d'importer des clés privées. Mais cette opération est importante si nous voulons travailler avec des jetons cloud PKCS # 11 .

Contrairement au jeton cryptographique PKCS # 11, le conteneur sécurisé PKCS # 12 n'est pas une machine cryptographique, c'est-à-dire il ne stocke que le certificat et la clé privée sous une forme sécurisée (cryptée avec un mot de passe) et n'effectue aucune opération cryptographique. Les exigences pour un conteneur sécurisé basé sur la cryptographie russe sont formulées par TK-26 dans le document «R 50.1.112-2016. Conteneur de clés de transport . », Qui a été approuvé et appliqué par l'ordonnance de l'Agence fédérale de réglementation technique et de métrologie du 23 novembre 2016 n ° 1753-st.

Comment obtenir le conteneur PKCS # 12 auprès du fournisseur de cryptographie MS CSP est bien décrit dans l'un des articles sur Habr.

Pour travailler avec PKCS # 12, j'ai dû développer deux nouveaux packages tcl, en plus du TclPKCS11 précédemment créé. Le premier package Lcc pour prendre en charge la cryptographie russe, en tenant compte des recommandations du TK-26.

Les commandes prises en charge par Lcc peuvent être vues ici:
// Digest commands // gost3411_2012 Tcl_CreateObjCommand(interp, "lcc_gost3411_2012", gost3411_2012_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_ctx_create", gost3411_2012_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_ctx_update", gost3411_2012_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_ctx_final", gost3411_2012_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_ctx_delete", gost3411_2012_ctx_delete_Cmd, NULL, NULL); // gost3411_94 Tcl_CreateObjCommand(interp, "lcc_gost3411_94", gost3411_94_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_ctx_create", gost3411_94_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_ctx_update", gost3411_94_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_ctx_final", gost3411_94_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_ctx_delete", gost3411_94_ctx_delete_Cmd, NULL, NULL); // sha1 Tcl_CreateObjCommand(interp, "lcc_sha1", sha1_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_sha1_ctx_create", sha1_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_sha1_ctx_update", sha1_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_sha1_ctx_final", sha1_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_sha1_ctx_delete", sha1_ctx_delete_Cmd, NULL, NULL); // HMAC commands // gost3411hmac Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_hmac", gost3411_2012_hmac_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_hmac_ctx_create", gost3411_2012_hmac_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_hmac_ctx_update", gost3411_2012_hmac_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_hmac_ctx_final", gost3411_2012_hmac_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_hmac_ctx_delete", gost3411_2012_hmac_ctx_delete_Cmd, NULL, NULL); // gost3411_94_hmac Tcl_CreateObjCommand(interp, "lcc_gost3411_94_hmac", gost3411_94_hmac_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_hmac_ctx_create", gost3411_94_hmac_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_hmac_ctx_update", gost3411_94_hmac_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_hmac_ctx_final", gost3411_94_hmac_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_hmac_ctx_delete", gost3411_94_hmac_ctx_delete_Cmd, NULL, NULL); // PKCS#5 commands Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_pkcs5", gost3411_2012_pkcs5_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_94_pkcs5", gost3411_94_pkcs5_Cmd, NULL, NULL); // PKCS#12 PBA Tcl_CreateObjCommand(interp, "lcc_gost3411_94_pkcs12_pba", gost3411_94_pkcs12_pba_Cmd, NULL, NULL); // gost3411_2012 KDF Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_256_kdf", gost3411_2012_256_kdf_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_256_kdf_tree", gost3411_2012_256_kdf_tree_Cmd, NULL, NULL); // PRF TLS Tcl_CreateObjCommand(interp, "lcc_gost3411_94_prf_tls", gost3411_94_prf_tls_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_256_prf_tls", gost3411_2012_256_prf_tls_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3411_2012_512_prf_tls", gost3411_2012_512_prf_tls_Cmd, NULL, NULL); // gost3410-2012 commands // 256 bits Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_getGroupByOid", gost3410_2012_256_getGroupByOid_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_getGroupByDerOid", gost3410_2012_256_getGroupByDerOid_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_getGroupById", gost3410_2012_256_getGroupById_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_createPrivateKey", gost3410_2012_256_createPrivateKey_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_createPublicKey", gost3410_2012_256_createPublicKey_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_sign", gost3410_2012_256_sign_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_verify", gost3410_2012_256_verify_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_vko", gost3410_2012_256_vko_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_256_keg", gost3410_2012_256_keg_Cmd, NULL, NULL); // 512 bits Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_getGroupByOid", gost3410_2012_512_getGroupByOid_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_getGroupByDerOid", gost3410_2012_512_getGroupByDerOid_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_getGroupById", gost3410_2012_512_getGroupById_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_createPrivateKey", gost3410_2012_512_createPrivateKey_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_createPublicKey", gost3410_2012_512_createPublicKey_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_sign", gost3410_2012_512_sign_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_verify", gost3410_2012_512_verify_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_vko", gost3410_2012_512_vko_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost3410_2012_512_keg", gost3410_2012_512_keg_Cmd, NULL, NULL); // gost3410-2001-vko (with 3411-94) Tcl_CreateObjCommand(interp, "lcc_gost3410_2001_vko", gost3410_2001_vko_Cmd, NULL, NULL); // Magma commands // ECB Tcl_CreateObjCommand(interp, "lcc_magma_ecb_ctx_create", magma_ecb_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_ecb_ctx_update", magma_ecb_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_ecb_ctx_delete", magma_ecb_ctx_delete_Cmd, NULL, NULL); // CBC Tcl_CreateObjCommand(interp, "lcc_magma_cbc_ctx_create", magma_cbc_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_cbc_ctx_update", magma_cbc_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_cbc_ctx_delete", magma_cbc_ctx_delete_Cmd, NULL, NULL); // CTR Tcl_CreateObjCommand(interp, "lcc_magma_ctr_ctx_create", magma_ctr_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_ctr_ctx_update", magma_ctr_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_ctr_ctx_delete", magma_ctr_ctx_delete_Cmd, NULL, NULL); // OFB Tcl_CreateObjCommand(interp, "lcc_magma_ofb_ctx_create", magma_ofb_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_ofb_ctx_update", magma_ofb_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_ofb_ctx_delete", magma_ofb_ctx_delete_Cmd, NULL, NULL); // CFB Tcl_CreateObjCommand(interp, "lcc_magma_cfb_ctx_create", magma_cfb_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_cfb_ctx_update", magma_cfb_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_cfb_ctx_delete", magma_cfb_ctx_delete_Cmd, NULL, NULL); // OMAC Tcl_CreateObjCommand(interp, "lcc_magma_omac_ctx_create", magma_omac_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_omac_ctx_update", magma_omac_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_omac_ctx_final", magma_omac_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_omac_ctx_delete", magma_omac_ctx_delete_Cmd, NULL, NULL); // CTR_ACPKM Tcl_CreateObjCommand(interp, "lcc_magma_ctr_acpkm_ctx_create", magma_ctr_acpkm_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_ctr_acpkm_ctx_update", magma_ctr_acpkm_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_ctr_acpkm_ctx_delete", magma_ctr_acpkm_ctx_delete_Cmd, NULL, NULL); // OMAC_ACPKM Tcl_CreateObjCommand(interp, "lcc_magma_omac_acpkm_ctx_create", magma_omac_acpkm_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_omac_acpkm_ctx_update", magma_omac_acpkm_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_omac_acpkm_ctx_final", magma_omac_acpkm_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_omac_acpkm_ctx_delete", magma_omac_acpkm_ctx_delete_Cmd, NULL, NULL); // key export/import Tcl_CreateObjCommand(interp, "lcc_magma_key_export", magma_key_export_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_magma_key_import", magma_key_import_Cmd, NULL, NULL); // Kuznyechik commands // ECB Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ecb_ctx_create", kuznyechik_ecb_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ecb_ctx_update", kuznyechik_ecb_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ecb_ctx_delete", kuznyechik_ecb_ctx_delete_Cmd, NULL, NULL); // CBC Tcl_CreateObjCommand(interp, "lcc_kuznyechik_cbc_ctx_create", kuznyechik_cbc_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_cbc_ctx_update", kuznyechik_cbc_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_cbc_ctx_delete", kuznyechik_cbc_ctx_delete_Cmd, NULL, NULL); // CTR Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ctr_ctx_create", kuznyechik_ctr_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ctr_ctx_update", kuznyechik_ctr_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ctr_ctx_delete", kuznyechik_ctr_ctx_delete_Cmd, NULL, NULL); // OFB Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ofb_ctx_create", kuznyechik_ofb_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ofb_ctx_update", kuznyechik_ofb_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ofb_ctx_delete", kuznyechik_ofb_ctx_delete_Cmd, NULL, NULL); // CFB Tcl_CreateObjCommand(interp, "lcc_kuznyechik_cfb_ctx_create", kuznyechik_cfb_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_cfb_ctx_update", kuznyechik_cfb_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_cfb_ctx_delete", kuznyechik_cfb_ctx_delete_Cmd, NULL, NULL); // OMAC Tcl_CreateObjCommand(interp, "lcc_kuznyechik_omac_ctx_create", kuznyechik_omac_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_omac_ctx_update", kuznyechik_omac_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_omac_ctx_final", kuznyechik_omac_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_omac_ctx_delete", kuznyechik_omac_ctx_delete_Cmd, NULL, NULL); // CTR_ACPKM Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ctr_acpkm_ctx_create", kuznyechik_ctr_acpkm_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ctr_acpkm_ctx_update", kuznyechik_ctr_acpkm_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_ctr_acpkm_ctx_delete", kuznyechik_ctr_acpkm_ctx_delete_Cmd, NULL, NULL); // OMAC_ACPKM Tcl_CreateObjCommand(interp, "lcc_kuznyechik_omac_acpkm_ctx_create", kuznyechik_omac_acpkm_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_omac_acpkm_ctx_update", kuznyechik_omac_acpkm_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_omac_acpkm_ctx_final", kuznyechik_omac_acpkm_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_omac_acpkm_ctx_delete", kuznyechik_omac_acpkm_ctx_delete_Cmd, NULL, NULL); // key export/import Tcl_CreateObjCommand(interp, "lcc_kuznyechik_key_export", kuznyechik_key_export_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_kuznyechik_key_import", kuznyechik_key_import_Cmd, NULL, NULL); // gost28147 commands Tcl_CreateObjCommand(interp, "lcc_gost28147_getParamsByOid", gost28147_getParamsByOid_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_getParamsByDerOid", gost28147_getParamsByDerOid_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_getParamsById", gost28147_getParamsById_Cmd, NULL, NULL); // ECB Tcl_CreateObjCommand(interp, "lcc_gost28147_ecb_ctx_create", gost28147_ecb_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_ecb_ctx_update", gost28147_ecb_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_ecb_ctx_delete", gost28147_ecb_ctx_delete_Cmd, NULL, NULL); // CBC Tcl_CreateObjCommand(interp, "lcc_gost28147_cbc_ctx_create", gost28147_cbc_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_cbc_ctx_update", gost28147_cbc_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_cbc_ctx_delete", gost28147_cbc_ctx_delete_Cmd, NULL, NULL); // CNT Tcl_CreateObjCommand(interp, "lcc_gost28147_cnt_ctx_create", gost28147_cnt_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_cnt_ctx_update", gost28147_cnt_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_cnt_ctx_delete", gost28147_cnt_ctx_delete_Cmd, NULL, NULL); // CFB Tcl_CreateObjCommand(interp, "lcc_gost28147_cfb_ctx_create", gost28147_cfb_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_cfb_ctx_update", gost28147_cfb_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_cfb_ctx_delete", gost28147_cfb_ctx_delete_Cmd, NULL, NULL); // OMAC Tcl_CreateObjCommand(interp, "lcc_gost28147_omac_ctx_create", gost28147_omac_ctx_create_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_omac_ctx_update", gost28147_omac_ctx_update_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_omac_ctx_final", gost28147_omac_ctx_final_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "lcc_gost28147_omac_ctx_delete", gost28147_omac_ctx_delete_Cmd, NULL, NULL); // KDF Tcl_CreateObjCommand(interp, "lcc_gost28147_kdf", gost28147_kdf_Cmd, NULL, NULL); 

Comme vous pouvez le voir, le package prend en charge non seulement GOST R 34.10-2012 et GOST R 34.11-2012, mais prend également en charge les algorithmes de chiffrement Grasshopper et Magma.

Le deuxième package GostPfx est destiné à l'analyse d'un conteneur PKCS # 11. Ces packages ont été créés à partir de bibliothèques issues d'un CIPF certifié. Ce travail minutieux a été réalisé par mon collègue et camarade, auteur de nombreuses illustrations pour nos publications, V. Blazhnov. C'est la mise en œuvre de ces packages qui a permis de créer un utilitaire véritablement indépendant de la plateforme pour une utilisation dans la gestion électronique des documents. Lorsque vous travaillez avec le conteneur PKCS # 12 dans le langage de script Tcl, une fonctionnalité intéressante a été révélée. Un conteneur créé à l'aide d' openssl avec la prise en charge de la cryptographie russe est créé strictement dans l'encodage DER, et un conteneur créé à l'aide du package NSS est créé à l'aide de l'encodage BER, qui utilise des balises de longueur indéfinie (dans le champ de longueur de balise est la valeur 0x80). Et lors de l'utilisation du paquet asn Tcl standard pour analyser le conteneur PKCS # 12, il s'est avéré qu'il ne comprenait pas les constructions asn codées BER:

  if {$length == 0x080} { return -code error "Indefinite length BER encoding not yet supported" } 

L'analyse du package asn a montré qu'il suffit de remplacer la fonction :: asn :: asnGetLength:

 package require asn #   rename ::asn::asnGetLength ::asn::asnGetLength.orig #   proc ::asn::asnGetLength {data_var length_var} { upvar 1 $data_var data $length_var length asnGetByte data length if {$length == 0x080} { #     # Indefinite length BER encoding yet supported set lendata [string length $data] set tvl 1 set length 0 set data1 $data while {$tvl != 0} { ::asn::asnGetByte data1 peek_tag ::asn::asnPeekByte data1 peek_tag1 #    if {$peek_tag == 0x00 && $peek_tag1 == 0x00} { incr tvl -1 ::asn::asnGetByte data1 tag incr length 2 continue } #    if {$peek_tag1 == 0x80} { incr tvl if {$tvl > 0} { incr length 2 } ::asn::asnGetByte data1 tag } else { set l1 [string length $data1] ::asn::asnGetLength data1 ll set l2 [string length $data1] set l3 [expr $l1 - $l2] incr length $l3 incr length $ll incr length ::asn::asnGetBytes data1 $ll strt } } return # return -code error "Indefinite length BER encoding not yet supported" } if {$length > 0x080} { # The retrieved byte is a prefix value, and the integer in the # lower nibble tells us how many bytes were used to encode the # length data following immediately after this prefix. set len_length [expr {$length & 0x7f}] if {[string length $data] < $len_length} { return -code error \ "length information invalid, not enough octets left" } asnGetBytes data $len_length lengthBytes switch $len_length { 1 { binary scan $lengthBytes cu length } 2 { binary scan $lengthBytes Su length } 3 { binary scan \x00$lengthBytes Iu length } 4 { binary scan $lengthBytes Iu length } default { binary scan $lengthBytes H* hexstr scan $hexstr %llx length } } } return } 

Une telle usurpation d'identité vous permet de traiter des balises de longueur indéfinie.

Pour analyser le conteneur PKCS # 12, le package GostPfx est écrit:
 set OS [lindex $tcl_platform(os) 0] #   Lcc #   Lrnd namespace eval ::GostPfx { namespace export pfxParse pfxMacDataParse pfxGetAuthSafeTbs pfxHmacVerify namespace export pfxTbsParse pfxPbeDataParse pfxPbeKey pfxDataDecrypt namespace export pfxIdentityDataParse pfxCertBagsParse pfxKeyBagsParse namespace export pfxKeyBagDecrypt pfxKeyDataParse pfxDataEncrypt namespace export pfxCreateSingleCertKey pfxGetSingleCertKey pfxCreateLocalKeyID variable INTEGER_TAG 2 variable OCTET_STRING_TAG 4 variable OBJECT_IDENTIFIER_TAG 6 variable SEQUENCE_TAG 16 variable SET_TAG 17 variable BMP_STRING_TAG 30 variable oid_Gost_3411_94 "1 2 643 2 2 9" variable oid_Gost3411_2012_512 "1 2 643 7 1 1 2 3" variable oid_pkcs7_data "1 2 840 113549 1 7 1" variable oid_pkcs7_encrypted_data "1 2 840 113549 1 7 6" variable oid_pkcs5PBES2 "1 2 840 113549 1 5 13" variable oid_pBKDF2 "1 2 840 113549 1 5 12" variable oid_HMACgostR3411_94 "1 2 643 2 2 10" variable oid_tc26_hmac_gost_3411_2012_512 "1 2 643 7 1 1 4 2" variable oid_gost28147_89 "1 2 643 2 2 21" variable oid_PKCS12CertificateBag "1 2 840 113549 1 12 10 1 3" variable oid_PKCS9x509Certificate "1 2 840 113549 1 9 22 1" variable oid_friendlyName "1 2 840 113549 1 9 20" variable oid_localKeyID "1 2 840 113549 1 9 21" variable oid_pkcs8ShroudedKeyBag "1 2 840 113549 1 12 10 1 2" variable oid_tc26_gost_28147_89_param_A "1 2 643 7 1 2 5 1 1" variable oid_GostR3410_2001 "1 2 643 2 2 19" variable oid_GostR3411_94_with_GostR3410_2001 "1 2 643 2 2 3" variable oid_tc26_gost3410_2012_256 "1 2 643 7 1 1 1 1" variable oid_tc26_signwithdigest_gost3410_2012_256 "1 2 643 7 1 1 3 2" variable oid_tc26_gost3410_2012_512 "1 2 643 7 1 1 1 2" variable oid_tc26_signwithdigest_gost3410_2012_256 "1 2 643 7 1 1 3 3" } proc reverse {args} { set res [list] if {[llength $args] == 1} { set args [lindex $args 0] } foreach elem $args { set res [linsert $res 0 $elem] } return $res } #----------------------------------------------------------------------------- # asnGetOctetString : Retrieve arbitrary string. #----------------------------------------------------------------------------- proc ::asn::asnGet24OctetString {data_var string_var} { # Here we need the full decoder for length data. upvar 1 $data_var data $string_var string asnGetByte data tag if {$tag != 0x24} { return -code error \ [format "Expected Octet String 24 (0x24), but got %02x" $tag] } asnGetLength data length asnGetBytes data $length temp set string $temp return } # indata => dict: authSafe macData digestAlg digestParamset hmac proc ::GostPfx::pfxParse {indata} { variable INTEGER_TAG variable SEQUENCE_TAG set data $indata set dres [dict create] set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence data seqValue set tag_len [asn::asnPeekTag seqValue tag_var tag_type_var constr_var] if {$tag_var == $INTEGER_TAG} { asn::asnGetInteger seqValue version dict set dres "version" $version } else { error "pfxParse: Invalid PFX DER structure 1 tag=$tag_var" } set tag_len [asn::asnPeekTag seqValue tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue authSafe dict set dres "authSafe" $authSafe } else { error "pfxParse: Invalid PFX DER structure 2" } set tag_len [asn::asnPeekTag seqValue tag_var tag_type_var constr_var] # Optional if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue macData dict set dres "macData" $macData } } else { error "pfxParse: Invalid PFX DER structure 3" } return $dres } # macData => dict: salt iter proc ::GostPfx::pfxMacDataParse {macData} { variable INTEGER_TAG variable OCTET_STRING_TAG variable OBJECT_IDENTIFIER_TAG variable SEQUENCE_TAG set data $macData set dres [dict create] set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence data seqValue1 set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue1 seqValue2 set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue2 digestAlg dict set dres "digestAlg" $digestAlg } else { error "pfxMacDataParse: Invalid MAC data structure" } set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] # Optional if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue2 digestParamset dict set dres "digestParamset" $digestParamset } } set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString seqValue1 hmac dict set dres "hmac" $hmac } else { error "pfxMacDataParse: Invalid MAC data structure" } } else { error "pfxMacDataParse: Invalid MAC data structure" } set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString data salt dict set dres "salt" $salt } else { error "pfxMacDataParse: Invalid MAC data structure" } set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $INTEGER_TAG} { asn::asnGetInteger data iter dict set dres "iter" $iter } else { error "pfxMacDataParse: Invalid MAC data structure" } return $dres } # authSafeData => tbs proc ::GostPfx::pfxGetAuthSafeTbs {authSafeData} { variable OCTET_STRING_TAG variable OBJECT_IDENTIFIER_TAG set data $authSafeData set tbs "" set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier data oid } else { error "pfxGetAuthSafeTbs: Invalid AuthSafe structure" } set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_type_var == "CONTEXT"} { asn::asnGetContext data contextNumber contextVar encoding_type ::asn::asnPeekByte contextVar peek_tag ::asn::asnPeekByte contextVar peek_tag1 1 if {$peek_tag == 0x24 && $peek_tag1 == 0x80} { set contextVar1 $contextVar ::asn::asnGet24OctetString contextVar1 contextVar puts "pfxGetAuthSafeTbs=0x240x80" } set tag_len [asn::asnPeekTag contextVar tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString contextVar tbs } else { error "pfxGetAuthSafeTbs: Invalid AuthSafe structure" } } else { error "pfxGetAuthSafeTbs: Invalid AuthSafe structure" } return $tbs } #    PBA      UTF-16  BOM #      . #     unicode     #        . proc ::GostPfx::passwordToUtf16 {password} { binary scan [encoding convertto unicode $password] c* bytes set bytes_len [llength $bytes] for {set i 0} {$i < $bytes_len} {incr i 2} { set left [lindex $bytes $i] set right [lindex $bytes [expr {$i+1}]] lset bytes $i $right lset bytes [expr {$i+1}] $left } lappend bytes 0 0 set out [binary format c* $bytes] return $out } # returns 1 or 0 proc ::GostPfx::pfxHmacVerify {tbs hmac password hmacDigestAlg hmacKeySalt hmacKeyIter} { variable oid_Gost_3411_94 variable oid_Gost3411_2012_512 if {$hmacDigestAlg == $oid_Gost_3411_94} { set passwordUtf16 [passwordToUtf16 $password] set hmacPbaKey [lcc_gost3411_94_pkcs12_pba $passwordUtf16 $hmacKeySalt $hmacKeyIter] set hmacPba [lcc_gost3411_94_hmac $tbs $hmacPbaKey] if {$hmacPba != $hmac} { #     26 v 1.0  HMAC   - set hmacPbaKey [string range [lcc_gost3411_94_pkcs5 $password $hmacKeySalt $hmacKeyIter 96] 64 95] set hmacPba [lcc_gost3411_94_hmac $tbs $hmacPbaKey] if {$hmacPba != $hmac} { #puts "hmacPba != hmac" } else { #puts "TC 26 v 1.0 PBA HMAC OK" return 1 } } else { #puts "Obsolete PBA HMAC OK" return 1 } } else { if {$hmacDigestAlg == $oid_Gost3411_2012_512} { set hmacPbaKey [string range [lcc_gost3411_2012_pkcs5 $password $hmacKeySalt $hmacKeyIter 96] 64 95] set hmacPba [lcc_gost3411_2012_hmac 64 $tbs $hmacPbaKey] if {$hmacPba != $hmac} { #puts "hmacPba != hmac" } else { #puts "TC 26 v 2.0 PBA HMAC OK" return 1 } } else { error "pfxHmacVerify: Unsupported digest algorithm: $hmacDigestAlg" } } return 0 } proc ::GostPfx::p7mParse {p7m} { variable OCTET_STRING_TAG variable OBJECT_IDENTIFIER_TAG variable SEQUENCE_TAG variable INTEGER_TAG variable oid_pkcs7_data set seqValue2 $p7m set dres [dict create] set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_type_var == "CONTEXT"} { asn::asnGetContext seqValue2 contextNumber contextData encoding_type set tag_len [asn::asnPeekTag contextData tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence contextData seqValue3 set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $INTEGER_TAG} { asn::asnGetInteger seqValue3 version set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue3 seqValue4 set tag_len [asn::asnPeekTag seqValue4 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue4 oid2 if {$oid2 == $oid_pkcs7_data} { set tag_len [asn::asnPeekTag seqValue4 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue4 certsPbeData dict set dres "certsPbeData" $certsPbeData set tag_len [asn::asnPeekTag seqValue4 tag_var tag_type_var constr_var] if {$tag_type_var == "CONTEXT"} { ::asn::asnPeekByte seqValue4 peek_tag ::asn::asnPeekByte seqValue4 peek_tag1 1 if {$peek_tag == 0xA0 && $peek_tag1 == 0x80} { set seqValue4_80 $seqValue4 set seqValue4 [string range $seqValue4_80 2 {end-2}] asn::asnGetOctetString seqValue4 encrCerts } else { asn::asnGetContext seqValue4 contextNumber encrCerts encoding_type } dict set dres "encrCerts" $encrCerts } else { error "pfxTbsParse: Invalid encrypted certificates structure 1" } } else { error "pfxTbsParse: Invalid encrypted certificates structure 2" } } else { error "pfxTbsParse: Invalid encrypted certificates structure 3" } } else { error "pfxTbsParse: Invalid encrypted certificates structure 4" } } else { error "pfxTbsParse: Invalid encrypted certificates structure 5" } } else { error "pfxTbsParse: Invalid encrypted certificates structure 6" } } else { error "pfxTbsParse: Invalid encrypted certificates structure 7" } } else { error "pfxTbsParse: Invalid encrypted certificates structure 8" } return $dres } proc ::GostPfx::p7dParse {p7d} { variable OCTET_STRING_TAG variable OBJECT_IDENTIFIER_TAG variable SEQUENCE_TAG variable INTEGER_TAG variable oid_pkcs7_data set dres [dict create] set seqValue2 $p7d set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_type_var == "CONTEXT"} { asn::asnGetContext seqValue2 contextNumber contextData encoding_type ############## ::asn::asnPeekByte contextData peek_tag ::asn::asnPeekByte contextData peek_tag1 1 if {$peek_tag == 0x24 && $peek_tag1 == 0x80} { set contextVar1 $contextData ::asn::asnGet24OctetString contextVar1 contextData puts "p7dParse=0x240x80" } ################# set tag_len [asn::asnPeekTag contextData tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString contextData keyBags dict set dres "keyBags" $keyBags } else { error "pfxTbsParse: Invalid key bags structure 1" } } else { error "pfxTbsParse: Invalid key bags structure 2" } return $dres } # tbs => dict: keyBags certsPbeData encrCerts proc ::GostPfx::pfxTbsParse {tbs} { variable OCTET_STRING_TAG variable OBJECT_IDENTIFIER_TAG variable SEQUENCE_TAG variable INTEGER_TAG variable oid_pkcs7_data variable oid_pkcs7_encrypted_data set data $tbs set dres [dict create] # set dres [list] set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence data seqValue1 set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue1 seqValue2 set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue2 oid2 if {$oid2 == $oid_pkcs7_encrypted_data} { set dres [::GostPfx::p7mParse $seqValue2] } elseif {$oid2 == $oid_pkcs7_data} { # set gg [dict create] set gg [list] set gg [::GostPfx::p7dParse $seqValue2] foreach {l l1} $gg { dict set dres $l $l1 } } else { error "pfxTbsParse: Invalid encrypted certificates structure 9 oid2=$oid2, oid_pkcs7_encrypted_data=$oid_pkcs7_encrypted_data" } } else { error "pfxTbsParse: Invalid encrypted certificates structure 10" } } set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue1 seqValue2 set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue2 oid2 if {$oid2 == $oid_pkcs7_data} { # set gg [dict create] set gg [list] set gg [::GostPfx::p7dParse $seqValue2] foreach {l l1} $gg { dict set dres $l $l1 } } elseif {$oid2 == $oid_pkcs7_encrypted_data} { set gg [list] set gg [::GostPfx::p7mParse $seqValue2] foreach {l l1} $gg { dict set dres $l $l1 } } else { error "pfxTbsParse: Invalid key bags structure 3" } } else { error "pfxTbsParse: Invalid key bags structure 4" } } } else { error "pfxTbsParse: Invalid TBS structure 5" } return $dres } # oid_pkcs5PBES2, ... => dict: hmacKeySalt hmacKeyIter hmacAlg digestParamset cipherAlg cipherIV cipherParamset proc ::GostPfx::pfxPbeDataParse {pbeData} { variable OCTET_STRING_TAG variable OBJECT_IDENTIFIER_TAG variable SEQUENCE_TAG variable INTEGER_TAG variable oid_pkcs5PBES2 variable oid_pBKDF2 set data $pbeData set dres [dict create] set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier data oid1 if {$oid1 == $oid_pkcs5PBES2} { set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence data seqValue1 set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue1 seqValue2 set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue2 oid2 if {$oid2 == $oid_pBKDF2} { set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue2 seqValue3 set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString seqValue3 hmacKeySalt dict set dres "hmacKeySalt" $hmacKeySalt set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $INTEGER_TAG} { asn::asnGetInteger seqValue3 hmacKeyIter dict set dres "hmacKeyIter" $hmacKeyIter set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue3 seqValue4 set tag_len [asn::asnPeekTag seqValue4 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue4 hmacAlg dict set dres "hmacAlg" $hmacAlg set tag_len [asn::asnPeekTag seqValue4 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue4 digestParamset dict set dres "digestParamset" $digestParamset } } else { error "pfxPbeDataParse: Invalid PBKDF2 HMAC algorithm structure" } } else { error "pfxPbeDataParse: Invalid PBKDF2 HMAC algorithm structure" } } else { error "pfxPbeDataParse: Invalid PBKDF2 iteration count structure" } } else { error "pfxPbeDataParse: Invalid PBKDF2 salt structure" } } else { error "pfxPbeDataParse: Invalid PBKDF2 structure" } } else { error "pfxPbeDataParse: Invalid PBKDF2 structure" } } else { error "pfxPbeDataParse: Invalid PBKDF2 structure" } } set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue1 seqValue2 set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue2 cipherAlg dict set dres "cipherAlg" $cipherAlg set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue2 seqValue3 set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString seqValue3 cipherIV dict set dres "cipherIV" $cipherIV set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue3 cipherParamset dict set dres "cipherParamset" $cipherParamset } } else { error "pfxPbeDataParse: Invalid PBE cipher IV structure" } } else { error "pfxPbeDataParse: Invalid PBE cipher params structure" } } else { error "pfxPbeDataParse: Invalid PBE cipher algorithm structure" } } else { error "pfxPbeDataParse: Invalid PBE cipher algorithm structure" } } else { error "pfxPbeDataParse: Invalid PBE structure" } } else { error "pfxPbeDataParse: Invalid PBE structure" } } else { error "pfxPbeDataParse: Invalid PBE structure" } return $dres } # generates cipher key proc ::GostPfx::pfxPbeKey {password hmacAlg hmacKeySalt hmacKeyIter} { variable oid_HMACgostR3411_94 variable oid_tc26_hmac_gost_3411_2012_512 set key "" if {$hmacAlg == $oid_HMACgostR3411_94} { set key [lcc_gost3411_94_pkcs5 $password $hmacKeySalt $hmacKeyIter 32] } else { if {$hmacAlg == $oid_tc26_hmac_gost_3411_2012_512} { set key [lcc_gost3411_2012_pkcs5 $password $hmacKeySalt $hmacKeyIter 32] } else { error "pfxPbeKey: Unsupported PKCS5 HMAC algorithm $hmacAlg" } } return $key } # encrData => decrData proc ::GostPfx::pfxDataDecrypt {data alg paramset key iv} { variable oid_gost28147_89 puts "pfxDataDecrypt: paramset=$paramset" set out "" if {$alg == $oid_gost28147_89} { set dotted_paramset [string map {" " "."} $paramset] set par [lcc_gost28147_getParamsByOid $dotted_paramset] if {$par > 0} { set ctx [lcc_gost28147_cfb_ctx_create $par 0 $key $iv] if {$ctx > 0} { set out [lcc_gost28147_cfb_ctx_update $ctx $data] lcc_gost28147_cfb_ctx_delete $ctx } else { error "pfxDataDecrypt: Invalid cipher key or IV" } lcc_handle_free $par } else { error "pfxDataDecrypt: Unsupported cipher paramset $paramset" } } else { error "pfxDataDecrypt: Unsupported cipher algorithm $alg" } return $out } # plain data => encrData proc ::GostPfx::pfxDataEncrypt {data alg paramset key iv} { variable oid_gost28147_89 set out "" if {$alg == $oid_gost28147_89} { set dotted_paramset [string map {" " "."} $paramset] set par [lcc_gost28147_getParamsByOid $dotted_paramset] if {$par > 0} { set ctx [lcc_gost28147_cfb_ctx_create $par 1 $key $iv] if {$ctx > 0} { set out [lcc_gost28147_cfb_ctx_update $ctx $data] lcc_gost28147_cfb_ctx_delete $ctx } else { error "pfxDataEncrypt: Invalid cipher key or IV" } lcc_handle_free $par } else { error "pfxDataEncrypt: Unsupported cipher paramset $paramset" } } else { error "pfxDataEncrypt: Unsupported cipher algorithm $alg" } return $out } # SET => dict: friendlyName localKeyID proc ::GostPfx::pfxIdentityDataParse {identityData} { variable SEQUENCE_TAG variable OBJECT_IDENTIFIER_TAG variable OCTET_STRING_TAG variable SET_TAG variable BMP_STRING_TAG variable oid_friendlyName variable oid_localKeyID set data $identityData set dres [dict create] set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SET_TAG} { asn::asnGetSet data set1 while {1} { set tag_len [asn::asnPeekTag set1 tag_var tag_type_var constr_var] if {$tag_var != $SEQUENCE_TAG} { break } asn::asnGetSequence set1 seqValue3 set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue3 oid3 set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $SET_TAG} { asn::asnGetSet seqValue3 set2 set tag_len [asn::asnPeekTag set2 tag_var tag_type_var constr_var] if {$oid3 == $oid_friendlyName} { if {$tag_var == $BMP_STRING_TAG} { asn::asnGetString set2 friendlyName dict set dres "friendlyName" $friendlyName } else { error "pfxIdentityDataParse: friendlyName is not BMP STRING" } } else { if {$oid3 == $oid_localKeyID} { if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString set2 localKeyID dict set dres "localKeyID" $localKeyID } } else { error "pfxIdentityDataParse: localKeyID is not OCTET STRING" } } } else { error "pfxIdentityDataParse: Invalid structure" } } else { error "pfxIdentityDataParse: Invalid structure" } } } else { error "pfxIdentityDataParse: Invalid structure" } return $dres } # certBags => { {dict: certificat friendlyName localKeyID} ...} proc ::GostPfx::pfxCertBagsParse {certBags} { variable SEQUENCE_TAG variable OBJECT_IDENTIFIER_TAG variable OCTET_STRING_TAG variable SET_TAG variable BMP_STRING_TAG variable oid_PKCS12CertificateBag variable oid_PKCS9x509Certificate variable oid_friendlyName variable oid_localKeyID set data $certBags set lres {} set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence data seqValue1 set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] while {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue1 seqValue2 set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue2 oid1 if {$oid1 == $oid_PKCS12CertificateBag} { set dcert [dict create] set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_type_var == "CONTEXT"} { asn::asnGetContext seqValue2 contextNumber context1 encoding_type set tag_len [asn::asnPeekTag context1 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence context1 seqValue3 set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue3 oid2 if {$oid2 == $oid_PKCS9x509Certificate} { set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_type_var == "CONTEXT"} { asn::asnGetContext seqValue3 contextNumber context2 encoding_type set tag_len [asn::asnPeekTag context2 tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString context2 certificate dict set dcert "certificate" $certificate } else { error "pfxCertBagsParse: Invalid structure 0" } } else { error "pfxCertBagsParse: Invalid structure 1" } } else { error "pfxCertBagsParse: Invalid structure 2" } } else { error "pfxCertBagsParse: Invalid structure 3" } } else { error "pfxCertBagsParse: Invalid structure 4" } } else { error "pfxCertBagsParse: Invalid structure 5" } set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] set did [pfxIdentityDataParse $seqValue2] if {[dict exists $did friendlyName]} { dict set dcert "friendlyName" [dict get $did friendlyName] } if {[dict exists $did localKeyID]} { dict set dcert "localKeyID" [dict get $did localKeyID] } } else { error "pfxCertBagsParse: Invalid structure 6" } } else { error "pfxCertBagsParse: Invalid structure 7" } lappend lres $dcert set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] } } else { error "pfxCertBagsParse: Invalid structure 8" } return [reverse $lres] # return $lres } # SEQUENCE, {SEQUENCE, oid_pkcs8ShroudedKeyBag, ...} => { {dict: keyBag friendlyName localKeyID} ... } proc ::GostPfx::pfxKeyBagsParse {keyBags} { variable SEQUENCE_TAG variable OBJECT_IDENTIFIER_TAG variable OCTET_STRING_TAG variable SET_TAG variable oid_pkcs8ShroudedKeyBag set data $keyBags set lres {} set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence data seqValue2 while {1} { set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var != $SEQUENCE_TAG} { break } asn::asnGetSequence seqValue2 seqValue3 set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue3 oid2 if {$oid2 == $oid_pkcs8ShroudedKeyBag} { set dbag [dict create] set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_type_var == "CONTEXT"} { asn::asnGetContext seqValue3 contextNumber context2 encoding_type set tag_len [asn::asnPeekTag context2 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence context2 keyBag dict set dbag keyBag $keyBag } else { error "pfxKeyBagsParse: Invalid structure" } } else { error "pfxKeyBagsParse: Invalid structure" } set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $SET_TAG} { set did [pfxIdentityDataParse $seqValue3] if {[dict exists $did friendlyName]} { dict set dbag friendlyName [dict get $did friendlyName] } if {[dict exists $did localKeyID]} { dict set dbag localKeyID [dict get $did localKeyID] } } lappend lres $dbag } else { error "pfxKeyBagsParse: Invalid structure" } } else { error "pfxKeyBagsParse: Invalid structure" } } } else { error "pfxKeyBagsParse: Invalid structure" } return $lres } # keyBag password => decrKey proc ::GostPfx::pfxKeyBagDecrypt {keyBag password} { variable SEQUENCE_TAG variable OCTET_STRING_TAG set decrKey "" set data $keyBag set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence data pbeData set dpbe [pfxPbeDataParse $pbeData] if {[dict exists $dpbe hmacKeySalt]} { set hmacKeySalt [dict get $dpbe hmacKeySalt] } if {[dict exists $dpbe hmacKeyIter]} { set hmacKeyIter [dict get $dpbe hmacKeyIter] } if {[dict exists $dpbe hmacAlg]} { set hmacAlg [dict get $dpbe hmacAlg] } if {[dict exists $dpbe digestParamset]} { set digestParamset [dict get $dpbe digestParamset] } if {[dict exists $dpbe cipherAlg]} { set cipherAlg [dict get $dpbe cipherAlg] } if {[dict exists $dpbe cipherIV]} { set cipherIV [dict get $dpbe cipherIV] } if {[dict exists $dpbe cipherParamset]} { set cipherParamset [dict get $dpbe cipherParamset] } set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString data encrKey } else { error "pfxKeyBagDecrypt: Invalid structure" } set cipherKey [pfxPbeKey $password $hmacAlg $hmacKeySalt $hmacKeyIter] set decrKey [pfxDataDecrypt $encrKey $cipherAlg $cipherParamset $cipherKey $cipherIV] } else { error "pfxKeyBagDecrypt: Invalid structure" } return $decrKey } # decrKey => dict: version keyAlg gost3410Paramset gost3411Paramset keyValue proc ::GostPfx::pfxKeyDataParse {decrKey} { variable SEQUENCE_TAG variable INTEGER_TAG variable OBJECT_IDENTIFIER_TAG variable OCTET_STRING_TAG set dKey [dict create] set data $decrKey set tag_len [asn::asnPeekTag data tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence data seqValue1 set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $INTEGER_TAG} { asn::asnGetInteger seqValue1 version dict set dKey version $version set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue1 seqValue2 set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue2 keyAlg dict set dKey keyAlg $keyAlg set tag_len [asn::asnPeekTag seqValue2 tag_var tag_type_var constr_var] if {$tag_var == $SEQUENCE_TAG} { asn::asnGetSequence seqValue2 seqValue3 set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue3 gost3410Paramset dict set dKey gost3410Paramset $gost3410Paramset set tag_len [asn::asnPeekTag seqValue3 tag_var tag_type_var constr_var] if {$tag_var == $OBJECT_IDENTIFIER_TAG} { asn::asnGetObjectIdentifier seqValue3 gost3411Paramset dict set dKey gost3411Paramset $gost3411Paramset } } else { error "pfxKeyDataParse: Invalid key paramset structure" } } else { error "pfxKeyDataParse: Invalid key paramset structure" } } else { error "pfxKeyDataParse: Invalid key algorithm structure" } } else { error "pfxKeyDataParse: Invalid key algorithm structure" } set tag_len [asn::asnPeekTag seqValue1 tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString seqValue1 octets1 set tag_len [asn::asnPeekTag octets1 tag_var tag_type_var constr_var] if {$tag_var == $OCTET_STRING_TAG} { asn::asnGetOctetString octets1 keyValue dict set dKey keyValue $keyValue } else { error "pfxKeyDataParse: Invalid key value structure" } } else { error "pfxKeyDataParse: Invalid key value structure" } } else { error "pfxKeyDataParse: Invalid key info structure" } } else { error "pfxKeyDataParse: Invalid key info structure" } return $dKey } # => dict: proc ::GostPfx::pfxGetSingleCertKey {indata password} { set dres [dict create] #puts "pfxParse" set dpfx [pfxParse $indata] if {[dict exists $dpfx authSafe]} { set authSafe [dict get $dpfx authSafe] } if {[dict exists $dpfx macData]} { set macData [dict get $dpfx macData] } #puts "pfxMacDataParse" set dhmac [pfxMacDataParse $macData] if {[dict exists $dhmac salt]} { set hmacKeySalt [dict get $dhmac salt] } if {[dict exists $dhmac iter]} { set hmacKeyIter [dict get $dhmac iter] } if {[dict exists $dhmac digestAlg]} { set hmacDigestAlg [dict get $dhmac digestAlg] } if {[dict exists $dhmac hmac]} { set hmac [dict get $dhmac hmac] } #puts "pfxGetAuthSafeTbs" set tbs [pfxGetAuthSafeTbs $authSafe] #puts "pfxHmacVerify" set hmac_ok [pfxHmacVerify $tbs $hmac $password $hmacDigestAlg $hmacKeySalt $hmacKeyIter] if {$hmac_ok != 1} { error "pfxGetSingleKeyCert: Check integrity: Invalid password or container corrupted!" } #puts "pfxTbsParse" set dKeysCertsData [pfxTbsParse $tbs] if {[dict exists $dKeysCertsData keyBags]} { set keyBags [dict get $dKeysCertsData keyBags] } if {[dict exists $dKeysCertsData certsPbeData]} { set certsPbeData [dict get $dKeysCertsData certsPbeData] } if {[dict exists $dKeysCertsData encrCerts]} { set encrCerts [dict get $dKeysCertsData encrCerts] } #puts "pfxPbeDataParse" set dCertsPbe [pfxPbeDataParse $certsPbeData] if {[dict exists $dCertsPbe hmacKeySalt]} { set hmacKeySalt [dict get $dCertsPbe hmacKeySalt] } if {[dict exists $dCertsPbe hmacKeyIter]} { set hmacKeyIter [dict get $dCertsPbe hmacKeyIter] } if {[dict exists $dCertsPbe hmacAlg]} { set hmacAlg [dict get $dCertsPbe hmacAlg] } if {[dict exists $dCertsPbe digestParamset]} { set digestParamset [dict get $dCertsPbe digestParamset] } if {[dict exists $dCertsPbe cipherAlg]} { set cipherAlg [dict get $dCertsPbe cipherAlg] } if {[dict exists $dCertsPbe cipherIV]} { set cipherIV [dict get $dCertsPbe cipherIV] } if {[dict exists $dCertsPbe cipherParamset]} { set cipherParamset [dict get $dCertsPbe cipherParamset] } #puts "pfxPbeKey" set cipherKey [pfxPbeKey $password $hmacAlg $hmacKeySalt $hmacKeyIter] #puts "pfxDataDecrypt" set certBags [pfxDataDecrypt $encrCerts $cipherAlg $cipherParamset $cipherKey $cipherIV] #puts "pfxCertBagsParse" set lcerts [pfxCertBagsParse $certBags] set dcert [lindex $lcerts 0] if {[dict exists $dcert "certificate"]} { set cert [dict get $dcert "certificate"] dict set dRes certificate $cert } if {[dict exists $dcert "friendlyName"]} { set cert_friendlyName [dict get $dcert "friendlyName"] } if {[dict exists $dcert "localKeyID"]} { set cert_localKeyID [dict get $dcert "localKeyID"] } #puts "pfxKeyBagsParse" set lKeyBags [pfxKeyBagsParse $keyBags] set dKeyBag [lindex $lKeyBags 0] if {[dict exists $dKeyBag keyBag]} { set keyBag [dict get $dKeyBag keyBag] } if {[dict exists $dKeyBag friendlyName]} { set key_friendlyName [dict get $dKeyBag friendlyName] dict set dRes friendlyName $key_friendlyName if {[info exists cert_friendlyName] && ($cert_friendlyName != $key_friendlyName)} { puts "pfxGetSingleKeyCert: Warning: certificate friendlyName: $cert_friendlyName is not equal to key friendlyName: $key_friendlyName" } } if {[dict exists $dKeyBag localKeyID]} { set key_localKeyID [dict get $dKeyBag localKeyID] dict set dRes localKeyID $key_localKeyID if {[info exists cert_localKeyID] && ($cert_localKeyID != $key_localKeyID)} { puts "pfxGetSingleKeyCert: Warning: certificate localKeyID is not equal to key localKeyID" } } #puts "pfxKeyBagDecrypt" set decrKey [pfxKeyBagDecrypt $keyBag $password] #puts "pfxKeyDataParse" set dKey [pfxKeyDataParse $decrKey] if {[dict exists $dKey version]} { set version [dict get $dKey version] } if {[dict exists $dKey keyAlg]} { set keyAlg [dict get $dKey keyAlg] dict set dRes keyAlg $keyAlg } if {[dict exists $dKey gost3410Paramset]} { set gost3410Paramset [dict get $dKey gost3410Paramset] dict set dRes gost3410Paramset $gost3410Paramset } if {[dict exists $dKey gost3411Paramset]} { set gost3411Paramset [dict get $dKey gost3411Paramset] dict set dRes gost3411Paramset $gost3411Paramset } if {[dict exists $dKey keyValue]} { set keyValue [dict get $dKey keyValue] dict set dRes keyValue $keyValue } return $dRes } proc ::GostPfx::pfxCreateSingleCertKey {password certificate keyValue keyAlg gost3410Paramset gost3411Paramset friendlyName localKeyID} { variable oid_Gost3411_2012_512 variable oid_gost28147_89 variable oid_tc26_gost_28147_89_param_A variable oid_tc26_hmac_gost_3411_2012_512 variable oid_pkcs5PBES2 variable oid_pBKDF2 variable oid_friendlyName variable oid_localKeyID variable oid_pkcs8ShroudedKeyBag variable oid_pkcs7_data variable oid_pkcs7_encrypted_data variable oid_PKCS12CertificateBag variable oid_PKCS9x509Certificate set pfx "" set ctx [lrnd_random_ctx_create ""] # create identityData set friendlyNameData [asn::asnSequence [asn::asnObjectIdentifier $oid_friendlyName] [asn::asnSet [asn::asnBMPString $friendlyName]]] set localKeyIDData [asn::asnSequence [asn::asnObjectIdentifier $oid_localKeyID] [asn::asnSet [asn::asnOctetString $localKeyID]]] set identityData [asn::asnSet $friendlyNameData $localKeyIDData] # create private key data set oid3410Paramset [asn::asnObjectIdentifier $gost3410Paramset] set oid3411Paramset [asn::asnObjectIdentifier $gost3411Paramset] set paramsetSequence [asn::asnSequence $oid3410Paramset $oid3411Paramset] set oidKeyAlg [asn::asnObjectIdentifier $keyAlg] set keyAlgSequence [asn::asnSequence $oidKeyAlg $paramsetSequence] set keyOctets [asn::asnOctetString [asn::asnOctetString $keyValue]] set version [asn::asnInteger 0] set keyData [asn::asnSequence $version $keyAlgSequence $keyOctets] # create private key cipherKey set keySalt [lrnd_random_ctx_get_bytes $ctx 32] set cipherKeyIter 2048 set hmacAlg $oid_tc26_hmac_gost_3411_2012_512 set keyCipherKey [pfxPbeKey $password $hmacAlg $keySalt $cipherKeyIter] # create cipher algorithm and params set cipherAlg $oid_gost28147_89 set cipherParamset $oid_tc26_gost_28147_89_param_A set keyCipherIV [lrnd_random_ctx_get_bytes $ctx 8] # encrypt private key data set encrKey [pfxDataEncrypt $keyData $cipherAlg $cipherParamset $keyCipherKey $keyCipherIV] # create private key PbeData set keyCipherParams [asn::asnSequence [asn::asnOctetString $keyCipherIV] [asn::asnObjectIdentifier $cipherParamset]] set keyCipherData [asn::asnSequence [asn::asnObjectIdentifier $cipherAlg] $keyCipherParams] set hmacAlgData [asn::asnSequence [asn::asnObjectIdentifier $oid_tc26_hmac_gost_3411_2012_512] [asn::asnNull]] set keyHmacData [asn::asnSequence [asn::asnOctetString $keySalt] [asn::asnInteger $cipherKeyIter] $hmacAlgData] set keyPbkdf2Data [asn::asnSequence [asn::asnObjectIdentifier $oid_pBKDF2] $keyHmacData] set keyPbeData [asn::asnSequence [asn::asnObjectIdentifier $oid_pkcs5PBES2] [asn::asnSequence $keyPbkdf2Data $keyCipherData]] # create keyBag set keyBagContext [asn::asnContextConstr 0 [asn::asnSequence $keyPbeData [asn::asnOctetString $encrKey]]] set keyBag [asn::asnSequence [asn::asnObjectIdentifier $oid_pkcs8ShroudedKeyBag] $keyBagContext $identityData] # create keyBags set keyBags [asn::asnOctetString [asn::asnSequence $keyBag]] set keysData [asn::asnSequence [asn::asnObjectIdentifier $oid_pkcs7_data] [asn::asnContextConstr 0 $keyBags]] # create certificate cipherKey set certSalt [lrnd_random_ctx_get_bytes $ctx 32] set certCipherKey [pfxPbeKey $password $hmacAlg $certSalt $cipherKeyIter] # create cipher algorithm and params set certCipherIV [lrnd_random_ctx_get_bytes $ctx 8] # create certPbeData set certCipherParams [asn::asnSequence [asn::asnOctetString $certCipherIV] [asn::asnObjectIdentifier $cipherParamset]] set certCipherData [asn::asnSequence [asn::asnObjectIdentifier $cipherAlg] $certCipherParams] set certHmacData [asn::asnSequence [asn::asnOctetString $certSalt] [asn::asnInteger $cipherKeyIter] $hmacAlgData] set certPbkdf2Data [asn::asnSequence [asn::asnObjectIdentifier $oid_pBKDF2] $certHmacData] set certPbeData [asn::asnSequence [asn::asnObjectIdentifier $oid_pkcs5PBES2] [asn::asnSequence $certPbkdf2Data $certCipherData]] # create certData set certData [asn::asnSequence [asn::asnObjectIdentifier $oid_PKCS9x509Certificate] [asn::asnContextConstr 0 [asn::asnOctetString $certificate]]] set certBag [asn::asnSequence [asn::asnObjectIdentifier $oid_PKCS12CertificateBag] [asn::asnContextConstr 0 $certData] $identityData] # create certBags set certBags [asn::asnSequence $certBag] # encrypt certBags set encrCertBags [pfxDataEncrypt $certBags $cipherAlg $cipherParamset $certCipherKey $certCipherIV] # create certsInfo (non-constructed context here!) set certsContent [asn::asnSequence [asn::asnObjectIdentifier $oid_pkcs7_data] $certPbeData [asn::asnContext 0 $encrCertBags]] set certsEncrData [asn::asnSequence [asn::asnInteger 0] $certsContent] set certsData [asn::asnSequence [asn::asnObjectIdentifier $oid_pkcs7_encrypted_data] [asn::asnContextConstr 0 $certsEncrData]] # create tbs set tbs [asn::asnSequence $certsData $keysData] # create hmacKey set hmacKeySalt [lrnd_random_ctx_get_bytes $ctx 32] set hmacPbaKey [string range [lcc_gost3411_2012_pkcs5 $password $hmacKeySalt $cipherKeyIter 96] 64 95] # create hmac set hmacPba [lcc_gost3411_2012_hmac 64 $tbs $hmacPbaKey] # create macData set digestParams [asn::asnSequence [asn::asnObjectIdentifier $oid_Gost3411_2012_512] [asn::asnNull]] set hmacData [asn::asnSequence $digestParams [asn::asnOctetString $hmacPba]] set macData [asn::asnSequence $hmacData [asn::asnOctetString $hmacKeySalt] [asn::asnInteger $cipherKeyIter]] # create pfx set pfxData [asn::asnSequence [asn::asnObjectIdentifier $oid_pkcs7_data] [asn::asnContextConstr 0 [asn::asnOctetString $tbs]]] set pfx [asn::asnSequence [asn::asnInteger 3] $pfxData $macData] lrnd_random_ctx_delete $ctx return $pfx } proc ::GostPfx::pfxCreateLocalKeyID {keyAlg gost3410Paramset privKeyValue} { variable oid_GostR3410_2001 variable oid_GostR3411_94_with_GostR3410_2001 variable oid_tc26_gost3410_2012_256 variable oid_tc26_signwithdigest_gost3410_2012_256 variable oid_tc26_gost3410_2012_512 variable oid_tc26_signwithdigest_gost3410_2012_512 set localKeyID "" if {($keyAlg == $oid_GostR3410_2001) || ($keyAlg == $oid_GostR3411_94_with_GostR3410_2001) || \ ($keyAlg == $oid_tc26_gost3410_2012_256) || ($keyAlg == $oid_tc26_signwithdigest_gost3410_2012_256)} { set par_id [string map {" " "."} $gost3410Paramset] set group [lcc_gost3410_2012_256_getGroupByOid $par_id] if {$group > 0} { set pubKey [lcc_gost3410_2012_256_createPublicKey $group $privKeyValue] } else { error "pfxCreateLocalKeyID: Unsupported paramset $gost3410Paramset" } } else { if {($keyAlg == $oid_tc26_gost3410_2012_512) || ($keyAlg == $oid_tc26_signwithdigest_gost3410_2012_512)} { set par_id [string map { } {.} $gost3410Paramset] set group [lcc_gost3410_2012_512_getGroupByOid $par_id] if {$group > 0} { set pubKey [lcc_gost3410_2012_512_createPublicKey $group $privKeyValue] } else { error "pfxCreateLocalKeyID: Unsupported paramset $gost3410Paramset" } } else { error "pfxCreateLocalKeyID: Unsupported algorithm: $keyAlg" } } set octets [asn::asnOctetString $pubKey] set localKeyID [lcc_sha1 $octets] return $localKeyID } package provide GostPfx 1.0.0 


, crytoarmpkcs, PKCS#12 , , :



, , , , , , OCSP.

:



.

, , . :



Vous pouvez également importer la clé privée dans le jeton:



il ne faut pas oublier que tous les jetons ne vous permettent pas d'y importer des clés privées. De notre point de vue, cette fonction est principalement nécessaire lors du stockage d'un certificat personnel dans un jeton cloud PKCS # 11 .

Et comment travailler avec les jetons PKCS # 11 a été décrit dans un article précédent .
Et il reste juste un peu (nous avons toujours le bouton «Réserver») - c'est le cryptage des documents sur le certificat du destinataire (sur une clé ouverte). Mais nous en parlerons la prochaine fois.

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


All Articles