Tcl / Tk-動的ライブラリに基づいた拡張機能/パッケージの作成

ノートの 1つでは、OpenSSLおよびNSS(ネットワークセキュリティサービス)パッケージ用のグラフィカルシェルを作成する意図が表明されました。 NSSのGUIは書かれています:



画像



今日、GOSTエンジンを搭載したopensslが、ロシアの広大なPKI(公開鍵インフラストラクチャ)でますます人気を得ていることに注意してください。



そして、それがTclのOpenSSL拡張の開発が非常に需要がある理由です。 そして、OpenSSL用のGUIを開発する方法を示しますが、opensslコマンドユーティリティに基づくのではなく、opensslライブラリ機能(libcrypto、libssl)を直接使用します。



画像 直接ネイティブライブラリは使用できません。 他の多くの場合(Javaの鮮やかな例)と同様に、Tclの機能を考慮してラッパー(ラップ)を記述する必要があります。 ただし、これらの機能は透過的であり、問​​題を引き起こすことはありません。



最初に、作成する拡張機能の構文を決定する必要がありますが、実際にはopenssl関数にアクセスするための構文です。 そのため、Tclプログラムは、改行またはセミコロンで区切られたコマンドで構成されます。 コマンドの最後に常にセミコロンを置くことをお勧めします。 次に、各コマンドは、スペースで区切られた一連のフィールドで構成されます。 最初のフィールドはコマンドの名前で、オプションの残りのフィールドはこのコマンドに渡される引数です。 コマンドは結果を返します。 これに基づいて、opensslユーティリティの構文に依存して、openssl拡張の次の構文を提案できます。



lscw <> [ 1] [ 2] … [ N];
      
      





ここで、lscwはコマンドの名前です。 <operation>フィールドは、opensslコマンドラインユーティリティ(たとえば、openssl x509)と同様に、実行されているサブ機能を示します。 サブ関数のパラメーターはその後に設定されます。



証明書(または証明書要求)のコンテンツを受信し、ウィジェットに表示する例を使用して、拡張機能、またはパッケージとも呼ばれるパッケージを作成することを検討します。 tclコマンドは次のようになります。



 set dump [lscw print $file_cert x ];
      
      





これは次のように解釈されます:証明書(パラメーターx)の内容(印刷パラメーター)を、パスが$ file変数に保存されているファイルのダンプ変数に保存します。 すべてのパラメーターは定位置です。 x / Xの代わりにr / Rが指定され、c / Cが失効した証明書のリストである場合、証明書要求の内容が印刷されます(PKCS#10)。



パッケージのコマンドのサポートは、対応するライブラリでサポートされています。 このライブラリをロードするには、Tclコマンドのロードを使用します。最も単純な場合は、次の形式です。



 load <> < >;
      
      





コマンドの最初のパラメーターはライブラリーの名前で、2番目は実装するパッケージの名前です。 これをすべて理解し、パッケージにlscwという名前を付けることを決定したら、拡張ライブラリをロードし、証明書付きのファイルを選択してウィンドウに表示できるようにするTcl / Tkスクリプトを作成できます( NSSには同様のスクリプトがあります):



 encoding system utf-8; #    . configure -background {#FFDAB9}; #    wm title . {GUI OpenSSL X509}; set homeDir $env(HOME); set types {{{ liblscw} {.so} } {{ liblscw MS} {.dll} } {{ } * } }; set typesCert { {{} {.crt} } {{} {.cer} } {{} {.der} } {{} {.pem} } {{ } * } }; #   wm iconify .; set liblscw [tk_getOpenFile -filetypes $types -initialdir $homeDir -title {    OpenSSL}]; if { $liblscw == {} } {exit 1}; # wrap-  OpenSSL if {[catch {load $liblscw lscw} res]} { puts $res; exit 1; }; set loadlib {loading shared lib: }; set loadlib $loadlib$liblscw; puts $loadlib; #puts {loading shared lib: $liblscw} set fileCert [tk_getOpenFile -filetypes $typesCert -initialdir $homeDir -title { /  }]; if { $fileCert == {} } {exit 1}; if {[catch {lscw print $fileCert x} res]} { puts $res; exit 1; }; #   wm deiconify .; # text-    text .prcert -background snow; pack .prcert -expand 1 -fill both -in . -pady 6 -padx 6; #  button .but -text  -command exit -background orange -activebackground green; pack .but -pady 6; #    .prcert delete 0.0 end ; #  .prcert insert end $res; #
      
      





コード自体に追加のコメントは必要ありません。 Cでライブラリを作成するだけです。OpenSSLの拡張機能と言えば、ロシアの暗号化をサポートすることに興味があります。 標準OpenSSLでは、このサポートはエンジンgostを通じて提供されます。 ライブラリがこのエンジンの接続を提供する理由です。



既に述べたように、ライブラリの読み込みはloadコマンドを介して行われます。最初のパラメータはライブラリへのパスを指定し、パッケージの2番目の名前を指定します。

パッケージ名は、実際には初期化プロシージャの名前を設定します。これはライブラリをロードした直後に呼び出されます。 初期化手順の名前は次のとおりです。



 < >_Init
      
      





初期化手順の命名のもう1つの特徴に言及します。パッケージ名の最初の文字は常に大文字に変換されます。 だからこそチーム



 load $liblscw lscw;
      
      





そしてチーム



 load $liblscw Lscw;
      
      





同一であり、両方の場合にライブラリをロードすると、Lscw_Init初期化プロシージャが呼び出されます。



 int Lscw_Init(Tcl_Interp* interp) { OpenSSL_add_all_algorithms(); #ifdef OPENSSL_GOST ENGINE_load_builtin_engines(); // - engine // gost = load_engine("/usr/lib64/openssl/1.0.2m/engines/libgost.so", 0); gost = load_engine("OPENSSL/libgost.so", 0); if (!ENGINE_set_default (gost, ENGINE_METHOD_ALL)) { Tcl_SetResult(interp, "OpenSSL error: ENGINE_set_default failed on engine", (Tcl_FreeProc*)0); return TCL_ERROR; } #endif //  lscw   lsrapCmd Tcl_CreateCommand(interp, "lscw", (Tcl_CmdProc *)lswrapCmd, (ClientData) 0, (void (*)()) NULL); return TCL_OK; }
      
      





完全なライブラリコードはこちらにあります。
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/pem.h> #include <openssl/engine.h> #include <tcl.h> #include <tk.h> #ifdef OPENSSL_GOST void ENGINE_load_gost(void); static ENGINE *gost; static ENGINE *load_engine(const char *engine, int debug); #endif char *X509View(char *nickfile, char typeX509); int lscwPrintSubCmd(ClientData lscmd, Tcl_Interp* interp); /*   */ typedef int ((*subProc)(ClientData, Tcl_Interp*)); /* */ typedef struct { char* subname; //  subProc f; //  int minStack; //  } subEntry; static subEntry subTable[] = { {"print", lscwPrintSubCmd, 2}, //   { 0, 0} }; int lscwPrintSubCmd(ClientData lscmd, Tcl_Interp* interp) { char **argv; char *res; argv = (void *)lscmd; res = (char *)X509View((char*)argv[2], (char)argv[3][0]); if (res == NULL) { //    Tcl Tcl_SetResult(interp, " .", (Tcl_FreeProc*)0); //  Tcl   TCL_ERROR return TCL_ERROR; } //    Tcl Tcl_SetResult(interp, res, (Tcl_FreeProc*)0); //  Tcl   TCL_ERROR return TCL_OK; } char *X509View(char *nickfile, char typeX509) { X509 *x509 = NULL; X509_REQ *x509_req = NULL; BIO *mem = BIO_new(BIO_s_mem()); char *p = NULL; char *res; int len; //  BIO *bio; if ( NULL == ( bio = BIO_new_file(nickfile, "rb"))){ fprintf(stderr, "X509View: failed to open file=%s\n", nickfile); return NULL; } switch(typeX509){ /*  X509*/ case 'x': case 'X': // DER x509 = d2i_X509_bio(bio, NULL); if (NULL == x509){ // PEM BIO_reset( bio ); x509 = PEM_read_bio_X509( bio, NULL, NULL, NULL ); if (NULL == x509){ BIO_free(bio); return NULL; } } #ifdef OPENSSL_GOST X509_print_ex(mem, x509, XN_FLAG_SEP_MULTILINE|ASN1_STRFLGS_UTF8_CONVERT, X509_FLAG_COMPAT); #else X509_print_ex(mem, x509, XN_FLAG_SEP_MULTILINE|ASN1_STRFLGS_UTF8_CONVERT, X509_FLAG_COMPAT); // X509_print(mem , x509); #endif X509_free(x509); break; /*    PKCS#10*/ case 'r': case 'R': // DER x509_req = d2i_X509_REQ_bio(bio, NULL); if (NULL == x509_req){ // PEM BIO_reset( bio ); x509_req = PEM_read_bio_X509_REQ( bio, NULL, NULL, NULL ); if (NULL == x509_req){ BIO_free(bio); return NULL; } } X509_REQ_print(mem, x509_req); X509_REQ_free(x509_req); break; /*    CRL*/ case 'c': case 'C': /* */ fprintf(stderr, " !!! file=%s, type=%c\n", nickfile, typeX509); break; defaut: return NULL; } len = BIO_get_mem_data(mem, &p); if(len == 0){ BIO_free(mem); fprintf(stderr, "BIO_get_mem_data ERROR!!! file=%s, type=%c\n", nickfile, typeX509); return NULL; } res = strdup(p); res[len - 1] = '\0'; BIO_free(mem); return res; } /*   */ static int lswrapCmd(ClientData dummy, Tcl_Interp* interp, int argc, char** argv) { int i; int retv; Tcl_ResetResult(interp); if (argc < 2) return TCL_ERROR; //  for(i = 0; subTable[i].subname != 0; i++) if(strcmp(argv[1], subTable[i].subname) == 0) { if((argc -2) != subTable[i].minStack){ char er[1024]; Tcl_SetResult(interp, "Usage: lircw Init gui|line", (Tcl_FreeProc*)0); sprintf(er, " not enough args: dano=%i, nado=%i ", (argc -2), subTable[i].minStack); Tcl_AppendResult(interp, er, (char*)0); return TCL_ERROR; } //  retv = subTable[i].f((void*)argv, interp); return retv; } if(subTable[i].subname == 0) { Tcl_AppendResult(interp, "   lscw: ", argv[1], 0); return TCL_ERROR; } } int Lscw_Init(Tcl_Interp* interp) { OpenSSL_add_all_algorithms(); #ifdef OPENSSL_GOST ENGINE_load_builtin_engines(); // - engine // gost = load_engine("/usr/lib64/openssl/1.0.2m/engines/libgost.so", 0); gost = load_engine("OPENSSL/libgost.so", 0); if (!ENGINE_set_default (gost, ENGINE_METHOD_ALL)) { fprintf(stderr, "OpenSSL error: ENGINE_set_default failed on engine \n"); return TCL_ERROR; } #endif Tcl_CreateCommand(interp, "lscw", (Tcl_CmdProc *)lswrapCmd, (ClientData) 0, (void (*)()) NULL); return TCL_OK; } #ifdef OPENSSL_GOST //  engine static ENGINE *load_engine(const char *engine, int debug) { ENGINE *e = ENGINE_by_id("dynamic"); if (e) { if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0) || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { ENGINE_free(e); e = NULL; } } return e; } #endif
      
      







アセンブリには、静的opensslライブラリが使用されました。



 $cc -shared -o liblscw.so -DOPENSSL_GOST -DUSE_INTERP_RESULT -fPIC openssl_print.c OPENSSL/libcrypto.a -ldl -pthread –lz $
      
      





アセンブリの後、記事の冒頭でスクリプトを安全に実行できます。



今こそ、ロシアの暗号化アルゴリズムをサポートするOpenSSLについて説明するときです。 残念ながら、OpenSSLの一部であるGOSTエンジンは、特に次の新しい暗号化アルゴリズムをサポートしていません。



画像 GOST R 34.11-2012の要件に準拠したハッシュ関数値の開発。 暗号化情報のセキュリティ。 ハッシュ関数」;



•GOST R 34.10-2012「情報技術の要件に従ったデジタル署名の形成と検証。 暗号化情報のセキュリティ。 電子デジタル署名の作成と検証のプロセス」;



•暗号化アルゴリズム「Grasshopper」(KUZmin、NECHAEV AND COMPANY)および「GOST R 34.12-2015 Information technology」の要件に従った「Magma」によるデータの暗号化/復号化。 暗号化情報のセキュリティ。 ブロック暗号」および「GOST R 34.13-2015情報技術。 暗号化情報のセキュリティ。 ブロック暗号の動作モード。」



まだ欠陥があります。 今日、ロシアのFSBの認証システムで認証されたものを含むOpenSSLの変更を見つけることができ、ロシアの暗号化を完全にサポートし、認定された証明書を含むすべての規制要件を満たします。 これらのプロジェクトの1つでコンパイルされたlscwライブラリは、 ここからダウンロードして 、認定された証明書を表示するために使用できます。



画像



そして最後に、tcl-scriptから離れて、実際のバイナリコードを取得したかったのです。 これを行うには、openssl_print_main.c Cコードの tclスクリプトを削除します



ソースコードopenssl_print_main.c
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <tcl.h> #include <tk.h> //  Tcl/Tk -  char strtcl[] = " \ encoding system utf-8; \ . configure -background {#FFDAB9}; \ wm title . {GUI OpenSSL X509}; \ set homeDir $env(HOME); \ set types {{{ liblscw} {.so} } \ {{ liblscw MS} {.dll} } \ {{ } * } \ }; \ set typesCert { {{} {.crt} } \ {{} {.cer} } \ {{} {.der} } \ {{} {.pem} } \ {{ } * } \ }; \ wm iconify . ; \ set liblscw [tk_getOpenFile -filetypes $types -initialdir $homeDir -title {    OpenSSL}]; \ if { $liblscw == {} } {exit 1}; \ if {[catch {load $liblscw} res]} { \ puts $res; \ exit 1; \ }; \ set loadlib {loading shared lib: } ; \ set loadlib $loadlib$liblscw ; \ puts $loadlib ; \ set fileCert [tk_getOpenFile -filetypes $typesCert -initialdir $homeDir -title { /  }]; \ if { $fileCert == {} } {exit 1}; \ if {[catch {lscw print $fileCert x} res]} { \ puts $res; \ exit 1; \ }; \ wm deiconify .; \ text .prcert -background snow; \ pack .prcert -expand 1 -fill both -in . -pady 6 -padx 6; \ button .but -text  -command exit -background orange -activebackground green; \ pack .but -pady 6; \ .prcert delete 0.0 end ; \ .prcert insert end $res; \ "; Tcl_Interp * tcl_interp ; main(int argc, char* argv[]){ int code; Tcl_FindExecutable(argv[0]); /* tcl-*/ tcl_interp = Tcl_CreateInterp(); /*  tcl-*/ Tcl_Init(tcl_interp); /* Tk-    tcl-*/ Tk_Init(tcl_interp); /*  Tcl/Tk   */ code = Tcl_Eval(tcl_interp, strtcl); /* Tcl/Tk      : code = Tcl_EvalFile(tcl_interp, filetcl); */ /*      lenstr   */ // code = Tcl_Eval(tcl_interp, ".but3 configure -command lenstr;"); /*   "lenstr"   lenStr   C-*/ // Tcl_CreateCommand(tcl_interp, "lenstr", (Tcl_CmdProc *)lenStr, NULL, NULL); Tk_MainLoop(); fprintf(stderr, "!\n"); return 0; }
      
      



私たちはそれを放送します

 $cc -o openssl_print_main openssl_print_main.c -ltcl –ltk $
      
      





そして作る:



 $./openssl_print_main
      
      





画像



ライブラリを選択し、次に証明書を選択して賞賛します(上記参照)。



Tcl / TkでOpenSSLを使用する最終プロジェクトは次のようになります。



画像



プロジェクトはこちらからダウンロードできます



Androidの場合、問題は今でも小規模です。



画像







All Articles