OpenSSLおよびCIPF Rutoken EDSを使用したブラウザーの電子署名

更新 ブラウザの電子署名用の既製のソリューション-Rutoken Plugin



「ブラウザ」での電子署名の実装を支援するソリューションの必要性が高まっています。 このようなソリューションの主な要件は、ロシアの暗号化アルゴリズム、キーセキュリティ、および通常の使いやすさのサポートです。 このトピックでは、OpenSSL GOSTがRootoken EDSサポートモジュールと統合されるブラウザーベースの暗号化Javaアプレットを作成します。 このアプレットは、クライアントソフトウェア(Javaマシンを除く)のインストールを必要とせず、Rutoken EDS USBトークンの「ボード」でロシア暗号化標準のハードウェア実装を使用して、PKCS#7形式のブラウザーでファイルに署名できます。 このトピックのデモでは、このアプレットを使用したHTMLページの例を示します。 このページでは、トークン内でキーを生成し、このキーの証明書用のPKCS#10アプリケーションを作成し、テスト証明書を取得し、トークンに書き込み、ファイルに署名できます。



ソリューションのアーキテクチャを図に示します:



画像



Rutoken EDSはコンパクトなUSBデバイスで、その内部には保護されたメモリとロシアの暗号化標準を実装するマイクロコントローラーがあります。 操作はトークンの「ボード」で実行されるため、ユーザーのキーを盗むことはできません。



OpenSSLは、ほとんどの最新の暗号化アルゴリズム、PKCS、CMS、S / MIME形式、SSL / TLSプロトコルなどをサポートするオープンソースのクロスプラットフォームパッケージです。 バージョン1.0.0以降、OpenSSLはロシアの暗号化アルゴリズムをフル機能でサポートします。



OpenSSLでRutoken EDSのサポートを提供するプラグインについては、ハブですぐに読むことができます。

habrahabr.ru/blogs/infosecurity/134725



Signatureライブラリは動的ライブラリであり、OpenSSL上の「アドオン」であり、OpenSSL呼び出し自体をカプセル化します。 Javaで使用するJNIインターフェイスを提供します。 このライブラリを作成します。



暗号化Javaアプレット





Eclipseでプロジェクトを作成する方法。 パッケージRutokenをプロジェクトに追加し、Signatureネイティブライブラリとの対話を担当するOpenSSLクラスと、アプレットから継承するOpenSSL_Wrapperクラスを追加します。



注意! それ以外の場合は、SignatureライブラリのJNIインターフェースの関数の名前を変更する必要があるため、名前は変更しないでください。



JavaアプレットがJARアーカイブ内にリソースとして保存する必要なすべてのライブラリーは、Webページにロードされると、それらを%TEMP%フォルダーに展開してそこから使用するため、必要なバイナリーをパッケージとしてリソースとして追加します。



バイナリの完全なリスト:



libeay32.dll-OpenSSLライブラリ

gost.dll-OpenSSLのGOSTアルゴリズムサポートモジュール

pkcs11_gost.dll-OpenSSLのRootoken EDSサポートモジュール

signature.dll-JNIインターフェースを提供するOpenSSL上の「アドオン」

rtPKCS11ECP.dll-Rootoken EDSのPKCS#11ライブラリ(ベンダーにより配布)

libp11.dll-PKCS#11ライブラリの「アドオン」

libltdl3.dll-追加ライブラリ



win32プラットフォーム用に収集されたライブラリは、 www.rutoken.ru / download / software / forum / openssl-rutoken-win32.zipからダウンロードできます。



リスト1. OpenSSLクラス



package Rutoken; import javax.swing.*; public class OpenSSL { static { try { System.load(OpenSSL_Wrapper.temp + "/libeay32.dll"); System.load(OpenSSL_Wrapper.temp + "/signature.dll"); } catch(Exception ex) { JOptionPane.showMessageDialog(null, ex.getMessage()); } } public native static int Init ( String install_path //     ); //     public native static int SaveCertToToken ( String cert, //   PEM String cert_file, //     PEM String slot_cert_id, // SLOT : ID  String label // label ); //      34-10.2001         PKCS#10 public native static String CreateKeyRequest ( String pin, // PIN-  String slot_key_id, // :ID  String paramset, //   String request_file, // ,      String common_name, //    String org, //  String org_unit, //   String city, //  String region, //  String country, //  String email, //   String keyUsages, //   ,  , String extendedKeyUsages //    ,  , ); //   PKCS#7    34.10-2001   PEM public native static String SignFile ( String pin, // PIN-  String slot_key_id, // :ID  String slot_cert_id, // :ID  String file_path, //   ,    int detached //  : 1-, 0- ); }
      
      







リスト2. OpenSSL_Wrapperクラス



 package Rutoken; import java.applet.Applet; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.swing.JOptionPane; public class OpenSSL_Wrapper extends Applet { public static String temp=System.getProperty("java.io.tmpdir")+"{rutoken-ecp-1983-8564}"; OpenSSL nativeObj; public void CopyResToFile(String resource, String file) { try { File f=new File(file); InputStream inputStream= getClass().getResourceAsStream(resource); OutputStream out=new FileOutputStream(f); byte buf[]=new byte[1024]; int len; while((len=inputStream.read(buf))>0) out.write(buf,0,len); out.close(); inputStream.close(); } catch (IOException e) {} } public void init() { File f = new File(temp); f.mkdir(); // openssl CopyResToFile("libeay32.dll", temp+"/libeay32.dll"); // openssl plugin CopyResToFile("gost.dll", temp+"/gost.dll"); // openssl plugin    CopyResToFile("pkcs11_gost.dll", temp+"/pkcs11_gost.dll"); //  PKCS#11    CopyResToFile("rtPKCS11ECP.dll", temp+"/rtPKCS11ECP.dll"); // libtool CopyResToFile("libltdl3.dll", temp+"/libltdl3.dll"); // openssl wrapper CopyResToFile("signature.dll", temp+"/signature.dll"); // PKCS#11 wrapper CopyResToFile("libp11.dll", temp+"/libp11.dll"); if(1!=OpenSSL.Init(temp)) { JOptionPane.showMessageDialog(null, "   OpenSSL!"); } } //     public int SaveCertToToken ( String cert, //   PEM String cert_file, //     PEM String slot_cert_id, // SLOT : ID  String label // label ) { return OpenSSL.SaveCertToToken(cert, cert_file, slot_cert_id, label); } //      34-10.2001         PKCS#10 public String CreateKeyRequest ( String pin, // PIN-  String slot_key_id, // :ID  String paramset, //   String request_file, // ,      String common_name, //    String org, //  String org_unit, //   String city, //  String region, //  String country, //  String email, //   String keyUsages, //   ,  , String extendedKeyUsages //    ,  , ) { return OpenSSL.CreateKeyRequest( pin, slot_key_id, paramset, request_file, common_name, org, org_unit, city, region, country, email, keyUsages, extendedKeyUsages); } //   PKCS#7    34.10-2001   PEM public String SignFile( String pin, // PIN-  String slot_key_id, // :ID  String slot_cert_id, // :ID  String file_path, //   ,    int detached //  : 1-, 0- ) { return OpenSSL.SignFile(pin, slot_key_id, slot_cert_id, file_path, detached); } }
      
      







パッケージRutokenをJARアーカイブにエクスポートし、jarsignerユーティリティを使用してこのアーカイブに署名する必要があります。



署名ライブラリ





次のAPIを実装します。



1.初期化関数:



 int init( const char* install_path );
      
      







2. Rutoken EDSでGOST R 34-10.2001署名キーを生成し、PKCS#10形式で証明書アプリケーションを作成する機能:



 char* create_key_request( const char* pin, /* PIN-  */ const char* slot_key_id, /* :ID  */ const char* paramset, /*   */ const char* request_file, /* ,      */ const char* common_name, /*    */ const char* org, /*  */ const char* org_unit, /*   */ const char* city, /*  */ const char* region, /*  */ const char* country, /*  */ const char* email, /* email */ const char* keyUsages, /*   ,  , */ const char* extendedKeyUsages /*    ,  , */ );
      
      







3. Rutoken EDSに証明書を記録する機能



 int save_pem_cert( const char* cert, /*   PEM */ const char* cert_file, /*    PEM */ const char* slot_cert_id, /* SLOT : ID  */ const char* label /* label */ );
      
      







4. GOST R 34.10-2001に準拠したPKCS#7形式のファイルに署名する機能:



 char* sign_file( const char* pin, /* PIN-  */ const char* slot_key_id, /* :ID  */ const char* slot_cert_id, /* :ID  */ const char* file_path, /*   ,    */ int detached /*  : 1-, 0- */ );
      
      







初期化関数には1つのパラメーターがあります。アプレットがバイナリーを解凍したフォルダーへのパスです。 これは、署名ライブラリがOpenSSL、そのプラグイン、およびRootoken EDSを操作するためのPKCS#11ライブラリをダウンロードするのに十分です。



Javaアプレットと対話するために、ライブラリはJNIインターフェイスも実装します。



リスト3.署名ライブラリーJNIインターフェースの実装



 #include <windows.h> #include "signature.h" #include <jni.h> #ifdef __cplusplus extern "C" { #endif JNIEXPORT jint JNICALL Java_Rutoken_OpenSSL_Init ( JNIEnv* env, jclass cl, jstring install_path ) { if(!install_path) return 0; return (jint)init((*env).GetStringUTFChars(install_path, false)); } JNIEXPORT jint JNICALL Java_Rutoken_OpenSSL_SaveCertToToken ( JNIEnv* env, jclass cl, jstring cert, //   PEM jstring cert_file, //     PEM jstring slot_cert_id, // SLOT : ID  jstring label ) { char* pCert = NULL; char* pCertFile = NULL; char* pId = NULL; char* pLabel = NULL; if( (!cert && !cert_file) || !slot_cert_id) return 0; if(cert) pCert=(char*)(*env).GetStringUTFChars(cert, false); if(cert_file) pCertFile=(char*)(*env).GetStringUTFChars(cert_file, false); pId=(char*)(*env).GetStringUTFChars(slot_cert_id, false); if(label) pLabel=(char*)(*env).GetStringUTFChars(label, false); return (jint)save_pem_cert( pCert, pCertFile, pId, pLabel); } JNIEXPORT jstring JNICALL Java_Rutoken_OpenSSL_CreateKeyRequest ( JNIEnv* env, jclass cl, jstring pin, // PIN-  jstring slot_key_id, // :ID  jstring paramset, //   jstring request_file, // ,      jstring common_name, //    jstring org, //  jstring org_unit, //   jstring city, //  jstring region, //  jstring country, //  jstring email, //   jstring keyUsages, //   ,  , jstring extendedKeyUsages //    ,  , ) { char* pPin = NULL; char* pSlotKeyId = NULL; char* pParamset = NULL; char* pCommonName = NULL; char* pOrg = NULL; char* pOrgUnit = NULL; char* pCity = NULL; char* pRegion = NULL; char* pCountry = NULL; char* pEmail = NULL; char* pKeyUsages = NULL; char* pExtendedKeyUsages = NULL; char* request = NULL; if(!pin || !slot_key_id || !paramset || !common_name || !email || !keyUsages || !extendedKeyUsages) return NULL; pPin=(char*)(*env).GetStringUTFChars(pin, false); pSlotKeyId=(char*)(*env).GetStringUTFChars(slot_key_id, false); pParamset=(char*)(*env).GetStringUTFChars(paramset, false); pCommonName=(char*)(*env).GetStringUTFChars(common_name, false); pOrg=(char*)(*env).GetStringUTFChars(org, false); pEmail=(char*)(*env).GetStringUTFChars(email, false); pKeyUsages=(char*)(*env).GetStringUTFChars(keyUsages, false); pExtendedKeyUsages=(char*)(*env).GetStringUTFChars(extendedKeyUsages, false); if(org) pOrg=(char*)(*env).GetStringUTFChars(org, false); if(org_unit) pOrgUnit=(char*)(*env).GetStringUTFChars(org_unit, false); if(city) pCity=(char*)(*env).GetStringUTFChars(city, false); if(region) pRegion=(char*)(*env).GetStringUTFChars(region, false); if(country) pCountry=(char*)(*env).GetStringUTFChars(country, false); request=(char*)create_key_request( pPin, pSlotKeyId, pParamset, NULL, pCommonName, pOrg, pOrgUnit, pCity, pRegion, pCountry, pEmail, pKeyUsages, pExtendedKeyUsages); if(request) return (*env).NewStringUTF((const char*)request); else return NULL; } JNIEXPORT jstring JNICALL Java_Rutoken_OpenSSL_SignFile ( JNIEnv* env, jclass cl, jstring pin, // PIN-  jstring slot_key_id, // :ID  jstring slot_cert_id, // :ID  jstring file_path, //   ,    jint detached ) { char* pPin = NULL; char* pKeyID = NULL; char* pCertID = NULL; char* pFilePath = NULL; char* signature = NULL; if(!pin || !slot_key_id || !slot_cert_id || !file_path) return NULL; pPin=(char*)(*env).GetStringUTFChars(pin, false); pKeyID=(char*)(*env).GetStringUTFChars(slot_key_id, false); pCertID=(char*)(*env).GetStringUTFChars(slot_cert_id, false); pFilePath=(char*)(*env).GetStringUTFChars(file_path, false); signature=sign_file( pPin, pKeyID, pCertID, pFilePath, (int)detached); if(signature) return (*env).NewStringUTF((const char*)signature); else return NULL; } #ifdef __cplusplus } #endif
      
      







リスト4. Signatureライブラリーの実装



 #include <windows.h> #include <openssl/lhash.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/crypto.h> /* for CRYPTO_* and SSLeay_version */ #include <openssl/rand.h> #include <openssl/md4.h> #include <openssl/des.h> #include <openssl/engine.h> #include <openssl/pkcs12.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/cms.h> #define CMD_LOAD_CERT_CTRL (ENGINE_CMD_BASE+5) #define CMD_SAVE_CERT_CTRL (ENGINE_CMD_BASE+6) #define CMD_LOGOUT (ENGINE_CMD_BASE+8) #define ENGINE_PKCS11_PIN_MESSAGE "PKCS#11 token PIN" char modules_path[MAX_PATH]; /*     engine_pkcs11 */ typedef struct _CERT_PKCS11_INFO { const char* s_slot_cert_id; X509* cert; const char* label; } CERT_PKCS11_INFO; /* callback  PIN- */ int pin_cb(UI *ui, UI_STRING *uis) { char* pPin=NULL; char* pString=NULL; pString=(char*)UI_get0_output_string(uis); if(!pString) return 0; if(!strncmp(pString, ENGINE_PKCS11_PIN_MESSAGE, strlen(ENGINE_PKCS11_PIN_MESSAGE))) { pPin=(char*)UI_get_app_data(ui); if(!pPin) return 0; UI_set_result(ui, uis, pPin); return 1; } else return 0; } /*     */ X509_EXTENSION* create_X509_extension ( char* name, char *value ) { X509_EXTENSION *ex; ex = X509V3_EXT_conf(NULL, NULL, name, value); if (!ex) return NULL; return ex; } ENGINE* engine_gost=NULL; ENGINE* LoadEngine(const char* pin) { ENGINE* engine_pkcs11=NULL; char enginePkcs11[MAX_PATH]; char engineGost[MAX_PATH]; char rtPkcs11ECP[MAX_PATH]; /*   engine GOST */ strcpy(engineGost, modules_path); strcat(engineGost, "\\gost.dll"); engine_gost=ENGINE_by_id("dynamic"); if(!engine_gost) return NULL; if(!ENGINE_ctrl_cmd_string(engine_gost, "SO_PATH", engineGost, 0) || !ENGINE_ctrl_cmd_string(engine_gost, "ID", "gost", 0) || !ENGINE_ctrl_cmd_string(engine_gost, "LOAD", NULL, 0)) return NULL; if(!ENGINE_init(engine_gost)) { ENGINE_free(engine_gost); return NULL; } /*   engine PKCS11 */ strcpy(enginePkcs11, modules_path); strcat(enginePkcs11, "\\pkcs11_gost.dll"); strcpy(rtPkcs11ECP, modules_path); strcat(rtPkcs11ECP, "\\rtPKCS11ECP.dll"); /* WARNING:    */ ENGINE_add(engine_gost); engine_pkcs11=ENGINE_by_id("dynamic"); if(!engine_pkcs11) return NULL; if(!ENGINE_ctrl_cmd_string(engine_pkcs11, "SO_PATH", enginePkcs11, 0) || !ENGINE_ctrl_cmd_string(engine_pkcs11, "ID", "pkcs11_gost", 0) || !ENGINE_ctrl_cmd_string(engine_pkcs11, "LOAD", NULL, 0) || !ENGINE_ctrl_cmd_string(engine_pkcs11, "MODULE_PATH", rtPkcs11ECP, 0)) return NULL; if(pin) { if(!ENGINE_ctrl_cmd_string(engine_pkcs11, "PIN", pin, 0)) return NULL; } if(!ENGINE_init(engine_pkcs11)) { ENGINE_free(engine_pkcs11); return NULL; } if(!ENGINE_set_default(engine_pkcs11, ENGINE_METHOD_ALL)) { ENGINE_free(engine_pkcs11); return NULL; } return engine_pkcs11; } X509_REQ* create_request ( EVP_PKEY* pKey, const char* common_name, /*    */ const char* org, /*  */ const char* org_unit, /*   */ const char* city, /*  */ const char* region, /*  */ const char* country, /*  */ const char* email, /*   */ const char* keyUsages, /*   ,  , */ const char* extendedKeyUsages /*    ,  ; */ ) { X509_REQ* req; X509_NAME* subject; BOOL bGoodEmail=TRUE; subject = X509_NAME_new(); if(common_name && strlen(common_name)>0) { if(!X509_NAME_add_entry_by_NID( subject, NID_commonName, MBSTRING_UTF8, (unsigned char*)common_name, -1, -1, 0)) { X509_NAME_free(subject); return NULL; } } if(org && strlen(org)>0) if(!X509_NAME_add_entry_by_NID( subject, NID_organizationName, MBSTRING_UTF8, (unsigned char*)org, -1, -1, 0)) { X509_NAME_free(subject); return NULL; } if(org_unit && strlen(org_unit)>0) if(!X509_NAME_add_entry_by_NID( subject, NID_organizationalUnitName, MBSTRING_UTF8, (unsigned char*)org_unit, -1, -1, 0)) { X509_NAME_free(subject); return NULL; } if(city && strlen(city)>0) if(!X509_NAME_add_entry_by_NID( subject, NID_localityName, MBSTRING_UTF8, (unsigned char*)city, -1, -1, 0)) { X509_NAME_free(subject); return NULL; } if(region && strlen(region)>0) if(!X509_NAME_add_entry_by_NID( subject, NID_stateOrProvinceName, MBSTRING_UTF8, (unsigned char*)region, -1, -1, 0)) { X509_NAME_free(subject); return NULL; } if(country && strlen(country)>0) if(!X509_NAME_add_entry_by_NID( subject, NID_countryName, MBSTRING_UTF8, (unsigned char*)country, -1, -1, 0)) { X509_NAME_free(subject); return NULL; } if(email && strlen(email)>0) { for (int i=0; i<strlen(email); i++) if (email[i]&0x80) { bGoodEmail=FALSE; break; } if(bGoodEmail) { if(!X509_NAME_add_entry_by_NID( subject, NID_pkcs9_emailAddress, MBSTRING_UTF8, (unsigned char*)email, -1, -1, 0)) { X509_NAME_free(subject); return NULL; } } } req=X509_REQ_new(); if(!req) { X509_NAME_free(subject); return NULL; } /*   */ if(!X509_REQ_set_version(req, 0)) { X509_REQ_free(req); X509_NAME_free(subject); return NULL; } /*  subject */ if(!X509_REQ_set_subject_name(req, subject)) { X509_REQ_free(req); X509_NAME_free(subject); return NULL; } /*    */ if(!X509_REQ_set_pubkey(req, pKey)) { X509_REQ_free(req); X509_NAME_free(subject); return NULL; } /* "digitalSignature,keyEncipherment" */ X509_EXTENSION* keyUsageExt = create_X509_extension("keyUsage", (char*)keyUsages); if(!keyUsageExt) { X509_REQ_free(req); X509_NAME_free(subject); return NULL; } /* "clientAuth,emailProtection" */ X509_EXTENSION* extendedKeyUsageExt = create_X509_extension("extendedKeyUsage", (char*)extendedKeyUsages); if(!extendedKeyUsageExt) { X509_EXTENSION_free(keyUsageExt); X509_REQ_free(req); X509_NAME_free(subject); return NULL; } STACK_OF(X509_EXTENSION)* extension_stack = sk_X509_EXTENSION_new_null(); if(!extension_stack) { X509_EXTENSION_free(extendedKeyUsageExt); X509_EXTENSION_free(keyUsageExt); X509_REQ_free(req); X509_NAME_free(subject); return NULL; } sk_X509_EXTENSION_push(extension_stack, keyUsageExt); sk_X509_EXTENSION_push(extension_stack, extendedKeyUsageExt); if(!X509_REQ_add_extensions(req, extension_stack)) { X509_EXTENSION_free(extendedKeyUsageExt); X509_EXTENSION_free(keyUsageExt); X509_REQ_free(req); X509_NAME_free(subject); return NULL; } if(!X509_REQ_sign(req, pKey, EVP_get_digestbyname("md_gost94"))) { X509_EXTENSION_free(extendedKeyUsageExt); X509_EXTENSION_free(keyUsageExt); X509_REQ_free(req); X509_NAME_free(subject); return NULL; } sk_X509_EXTENSION_pop_free (extension_stack,X509_EXTENSION_free); X509_NAME_free(subject); return req; } ENGINE* engine_pkcs11 = NULL; extern "C" __declspec( dllexport ) int init(const char* install_path) { HMODULE hLibp11 = NULL; HMODULE hLibTdl = NULL; char libp11[MAX_PATH]; char libtdl[MAX_PATH]; strcpy(modules_path, install_path); strcpy(libtdl, install_path); strcat(libtdl, "\\libltdl3.dll"); hLibTdl=LoadLibraryA(libtdl); if(!hLibTdl) return 0; strcpy(libp11, install_path); strcat(libp11, "\\libp11.dll"); hLibp11=LoadLibraryA(libp11); if(!hLibp11) return 0; /*  OpenSSL */ ENGINE_load_builtin_engines(); OPENSSL_add_all_algorithms_noconf(); engine_pkcs11=LoadEngine(NULL); if(!engine_pkcs11) return 0; return 1; } /*     */ extern "C" __declspec( dllexport ) int save_pem_cert ( const char* cert, /*   PEM */ const char* cert_file, /*     PEM */ const char* slot_cert_id, /* SLOT : ID  */ const char* label /* label */ ) { int len = 0; X509* x509 = NULL; BIO* bio_cert = NULL; BIO* bio_der = NULL; CERT_PKCS11_INFO cert_info; /*   */ if(cert) { bio_cert=BIO_new(BIO_s_mem()); if(!bio_cert) return 0; if(!BIO_puts(bio_cert, cert)) return 0; x509=PEM_read_bio_X509(bio_cert, NULL, NULL, NULL); if(!x509) { BIO_free(bio_cert); return 0; } } else if(cert_file) { bio_cert=BIO_new_file(cert_file, "rb"); if(!bio_cert) return 0; x509=PEM_read_bio_X509(bio_cert, NULL, NULL, NULL); if(!x509) { BIO_free(bio_cert); return 0; } } cert_info.s_slot_cert_id=slot_cert_id; cert_info.cert=x509; cert_info.label=label; if(!ENGINE_ctrl(engine_pkcs11, CMD_SAVE_CERT_CTRL, 0, (void*)&cert_info, NULL)) { return 0; } return 1; } /*      34-10.2001         PKCS#10 */ extern "C" __declspec( dllexport ) char* create_key_request( const char* pin, /* PIN-  */ const char* slot_key_id, /* :ID  */ const char* paramset, /*   */ const char* request_file, /* ,      */ const char* common_name, /*    */ const char* org, /*  */ const char* org_unit, /*   */ const char* city, /*  */ const char* region, /*  */ const char* country, /*  */ const char* email, /*   */ const char* keyUsages, /*   ,  , */ const char* extendedKeyUsages /*    ,  , */ ) { BIO* bio_req=NULL; BIO* bio_key=NULL; X509_REQ* pRequest=NULL; BUF_MEM* pbmReq; char* cRequest=NULL; UI_METHOD* uim=NULL; int reason=0; EVP_PKEY* key1=NULL; EVP_PKEY* newkey=NULL; EVP_PKEY_CTX* ctx=NULL; key1=EVP_PKEY_new(); if(!key1) { return NULL; } if(!EVP_PKEY_set_type(key1, 811)) { EVP_PKEY_free(key1); return NULL; } ctx=EVP_PKEY_CTX_new(key1, NULL); if(!ctx) { EVP_PKEY_free(key1); return NULL; } if(!EVP_PKEY_keygen_init(ctx)) { EVP_PKEY_CTX_free(ctx); return NULL; } if(!EVP_PKEY_CTX_ctrl_str(ctx, "paramset", paramset)) { EVP_PKEY_CTX_free(ctx); return NULL; } if(!EVP_PKEY_CTX_ctrl_str(ctx, "slot_key_id", slot_key_id)) { EVP_PKEY_CTX_free(ctx); return NULL; } if(!EVP_PKEY_CTX_ctrl_str(ctx, "pin", pin)) { EVP_PKEY_CTX_free(ctx); return NULL; } if(!EVP_PKEY_keygen(ctx,&newkey)) { EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } pRequest=create_request( newkey, common_name, org, org_unit, city, region, country, email, keyUsages, extendedKeyUsages); if(!pRequest) { EVP_PKEY_free(newkey); EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } bio_req=BIO_new(BIO_s_mem()); if(!bio_req) { X509_REQ_free(pRequest); EVP_PKEY_free(newkey); EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } if(!PEM_write_bio_X509_REQ(bio_req, pRequest)) { BIO_free(bio_req); X509_REQ_free(pRequest); EVP_PKEY_free(newkey); EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } BIO_get_mem_ptr(bio_req, &pbmReq); if(!pbmReq) { BIO_free(bio_req); X509_REQ_free(pRequest); EVP_PKEY_free(newkey); EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } cRequest=(char*)OPENSSL_malloc(pbmReq->length+1); if(!cRequest) { BIO_free(bio_req); X509_REQ_free(pRequest); EVP_PKEY_free(newkey); EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } memset(cRequest, 0, pbmReq->length+1); memcpy(cRequest, pbmReq->data, pbmReq->length); BIO_free(bio_req); bio_req=NULL; if(request_file) { bio_req=BIO_new_file(request_file, "wb"); if(!bio_req) { X509_REQ_free(pRequest); EVP_PKEY_free(newkey); EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } if(!PEM_write_bio_X509_REQ(bio_req, pRequest)) { BIO_free(bio_req); EVP_PKEY_free(newkey); EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } BIO_free(bio_req); } X509_REQ_free(pRequest); EVP_PKEY_free(newkey); EVP_PKEY_CTX_free(ctx); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return cRequest; } /*   PKCS#7    34-10.2001   PEM */ extern "C" __declspec( dllexport ) char* sign_file( const char* pin, /* PIN-  */ const char* slot_key_id, /* :ID  */ const char* slot_cert_id, /* :ID  */ const char* file_path, /*   ,    */ int detached /*  : 1-, 0- */ ) { BIO* bio_cert = NULL; BIO* in = NULL; BIO* out = NULL; BUF_MEM* pbmOut = NULL; EVP_PKEY* pKey = NULL; UI_METHOD* uim = NULL; PKCS7* p7 = NULL; char* pSignature = NULL; int flags = 0; int reason = 0; CERT_PKCS11_INFO cert_info; uim=UI_create_method("RutokenECP"); if(!uim) return NULL; UI_method_set_reader(uim, pin_cb); /*    */ pKey=ENGINE_load_private_key(engine_pkcs11, slot_key_id, uim, (void*)pin); if(!pKey) { /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } memset(&cert_info, 0, sizeof(cert_info)); cert_info.s_slot_cert_id=slot_cert_id; /*     */ if(!ENGINE_ctrl(engine_pkcs11, CMD_LOAD_CERT_CTRL, 0, &cert_info, NULL)) { EVP_PKEY_free(pKey); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } BIO_free(bio_cert); in=BIO_new_file(file_path, "rb"); if(!in) { EVP_PKEY_free(pKey); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } out=BIO_new(BIO_s_mem()); if(!out) { BIO_free(in); EVP_PKEY_free(pKey); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } if(detached) flags=PKCS7_DETACHED|PKCS7_BINARY; else flags=PKCS7_BINARY; /*  pkcs#7 */ p7=PKCS7_sign(cert_info.cert, pKey, NULL, in, flags); if(!p7) { BIO_free(out); BIO_free(in); EVP_PKEY_free(pKey); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } if(!PEM_write_bio_PKCS7(out, p7)) { PKCS7_free(p7); BIO_free(out); BIO_free(in); EVP_PKEY_free(pKey); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } BIO_get_mem_ptr(out, &pbmOut); if(!pbmOut) { PKCS7_free(p7); BIO_free(out); BIO_free(in); EVP_PKEY_free(pKey); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } pSignature=(char*)OPENSSL_malloc(pbmOut->length+1); if(!pSignature) { PKCS7_free(p7); BIO_free(out); BIO_free(in); EVP_PKEY_free(pKey); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return NULL; } memset(pSignature, 0, pbmOut->length+1); memcpy(pSignature, pbmOut->data, pbmOut->length); CRYPTO_cleanup_all_ex_data(); PKCS7_free(p7); BIO_free(out); BIO_free(in); EVP_PKEY_free(pKey); /* logout */ ENGINE_ctrl(engine_pkcs11, CMD_LOGOUT, 0, (void*)slot_key_id, NULL); return pSignature; }
      
      







希望する人は、このライブラリをクロスプラットフォームにする(LoadLibraryを適切な呼び出しに置き換える)ことができ、必要な機能でこのライブラリを拡張します。



HTMLデモページ





リスト5. JavaScriptがアプレットを使用するHTMLページの例



 <html><head> <title>-  </title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="keywords" content=""> </head> <body bgcolor="#ffffff"> <applet code="Rutoken.OpenSSL_Wrapper.class" archive="Rutoken.jar" height="0" width="0"> <table> <tbody><tr width="100%" bgcolor="#FFF8DC" valign="top"> <td align="right" height="40" valign="middle" width="10000"><span class="warning">     plugin JAVA.   JAVA   <a href="http://www.java.com/ru/download/windows_xpi.jsp?locale=ru">...</a></span> </td> </tr> </tbody></table> </applet> <center> <script type="text/javascript"> var loaded=0; function createKeyRequest() { var request; var pin; if(!document.getElementById("common_name").value) { alert("!\n  !.") return; } if(!document.getElementById("email").value) { alert("!\n email!.") return; } if(!document.getElementById("pin").value) { alert("!\n PIN!.") return; } pin=document.getElementById("pin").value; if(loaded==0) { var applet = "<applet id='RutokenApplet' style='visibility: hidden' name='RutokenApplet' archive='Rutoken.jar' code='Rutoken.OpenSSL_Wrapper.class' width='0' height='0'></applet>"; var body = document.getElementsByTagName("body")[0]; var div = document.createElement("div"); div.innerHTML = applet; body.appendChild(div); loaded=1; } request = document.RutokenApplet.CreateKeyRequest( pin, document.getElementById("keyId").value, "A", null, document.getElementById("common_name").value, document.getElementById("org").value, document.getElementById("org_unit").value, document.getElementById("city").value, document.getElementById("region").value, document.getElementById("country").value, document.getElementById("email").value, "digitalSignature,keyEncipherment", "clientAuth,emailProtection"); if(!request) { alert("     !"); return; } document.getElementById('request').value=request; } function saveCertToToken() { if (loaded == 0) { var applet = "<applet id='RutokenApplet' style='visibility: hidden' name='RutokenApplet' archive='Rutoken.jar' code='Rutoken.OpenSSL_Wrapper.class' width='0' height='0'></applet>"; var body = document.getElementsByTagName("body")[0]; var div = document.createElement("div"); div.innerHTML = applet; body.appendChild(div); loaded = 1; } if(!document.getElementById('certarea').value) { alert("    !"); return; } if (!document.RutokenApplet.SaveCertToToken(document.getElementById('certarea').value, null, document.getElementById("keyId").value, null)) { alert("     !"); return; } else { alert("!"); } } function signFile() { var signature; if (!document.getElementById("pin").value) { alert("!\n PIN!.") return; } if (!document.getElementById('fileForSign').value) { alert("   !"); return; } if (loaded == 0) { var applet = "<applet id='RutokenApplet' style='visibility: hidden' name='RutokenApplet' archive='Rutoken.jar' code='Rutoken.OpenSSL_Wrapper.class' width='0' height='0'></applet>"; var body = document.getElementsByTagName("body")[0]; var div = document.createElement("div"); div.innerHTML = applet; body.appendChild(div); loaded = 1; } signature=document.RutokenApplet.SignFile( document.getElementById("pin").value, document.getElementById("keyId").value, document.getElementById("keyId").value, document.getElementById('fileForSign').value, 1); if(!signature) { alert("   !"); return; } else { alert("!"); document.getElementById('signature').value = signature; } } </script> <table align="center" border="0" cellpadding="0" cellspacing="0" width="760"> <tbody><tr valign="top"> <td width="8""> </td> <td class="m9" align="center" width="125"> </td> <td><table align="center" width="600"><tbody><tr valign="top"><td width="20"> </td> <td> <!--BEGIN CONTENT--> <table border="0" cellpadding="5" cellspacing="0"> <tbody><tr valign="top"> <td><table bgcolor="" border="0" cellpadding="1" cellspacing="0"><tbody><tr><td> <table border="0" cellpadding="8" cellspacing="0" width="400"> <tbody> <tr> <td valign="top" width="400"> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td colspan="2" align="center" height="6"><h3> </h3> </td> </tr> <tr> <td colspan="2" height="10"> </td> </tr> <tr> <td colspan="2" align="center" height="6"><h4>   :</h4> </td> </tr> <tr> <td id="locNameAlign" align="left"><span id="spnNameLabel"><locid id="locNameLabel"><font size="-1">*:</font></locid></span> </td> <td><input id="common_name" maxlength="64" size="38" name="tbCommonName"> </td> </tr> <tr> <td colspan="2" height="18"> </td> </tr> <tr> <td id="locEmailAlign" align="left"><span id="spnEmailLabel"><locid id="locEmailLabel"><font size="-1">Email*:</font></locid></span> </td> <td><input id="email" maxlength="128" size="38" name="tbEmail"> </td> </tr> <tr> <td colspan="2" height="18"> </td> </tr> <tr><td id="locCompanyAlign" align="left"><span id="spnCompanyLabel"><locid id="locOrgLabel"><font size="-1">:</font></locid></span></td> <td><input id="org" maxlength="64" size="38" name="tbOrg"></td> </tr> <tr> <td colspan="2" height="18"> </td> </tr> <tr> <td id="locDepartmentAlign" align="left"><span id="spnDepartmentLabel"><locid id="locOrgUnitLabel"><font size="-1">:</font></locid></span></td> <td><input id="org_unit" maxlength="64" size="38" name="tbOrgUnit"></td></tr> <tr> <td colspan="2" height="18"> </td> </tr> <tr> </tr><tr> <td id="locCityAlign" align="left"><span id="spnCityLabel"><locid id="locLocalityLabel"><font size="-1">:</font></locid></span></td> <td><input id="city" maxlength="128" size="38" name="tbLocality"></td></tr> <tr> <td colspan="2" height="18"> </td> </tr> <tr> </tr><tr> <td id="locStateAlign" align="left"><span id="spnStateLabel"><locid id="locStateLabel"><font size="-1">, :</font></locid></span></td> <td><input id="region" maxlength="128" size="38" name="tbState"></td></tr> <tr> <td colspan="2" height="18"> </td> </tr> <tr> </tr><tr> <td id="locCountryAlign" align="left"><span id="spnCountryLabel"><locid id="locCountryLabel"><font size="-1">/:</font></locid></span></td> <td><input id="country" maxlength="2" size="38" value="RU" name="tbCountry"> </td> </tr> <tr> <td colspan="2" height="18"> </td> </tr> <tr> <td colspan="2" height="8"> </td> </tr> <tr> <td id="locKeyIDAlign" align="left"><span id="spnKeyId"><locid id="locKeyIDLabel"><font size="-1"> ID:</font></locid></span></td> <td><input id="keyId" maxlength="20" size="38" name="tbKeyID"></td> </tr> <tr> <td id="tdPin" align="left"><span id="spnPin"><locid id="locPin"><font size="-1"> PIN:</font></locid></span></td> <td><input id="pin" maxlength="20" size="38" type="password"></td> </tr> <tr> <td colspan="2" height="8"> </td> </tr> <tr> <td height="12"> </td> <td align="right"><input disable="true" value="    " onclick="createKeyRequest();" type="button"> </td> </tr> <tr> <td colspan="2" height="20"> </td> </tr> </tbody> </table> <table> <tbody> <tr> <td>     PKCS#10.     <a href="http://ca.cryptocom.ru"> </a></td> </tr> <tr> <td height="3"> </td> </tr> <tr> <td align="right"><textarea id="request" rows="6" cols="44" name="tbRequest"></textarea> </td> </tr> <tr> <td height="6"> </td> </tr> <tr> <td>        PEM  :</a></td> </tr> <tr> <td height="3"> </td> </tr> <tr> <td align="right"><textarea id="certarea" rows="6" cols="44" name="tbCertArea"></textarea> </td> </tr> <tr> <td align="right"><input disable="true" value="    " onclick="saveCertToToken();" type="button"> </td> </tr> <tr> <td height="6"> </td> </tr> <tr> <td>     :</a></td> </tr> <tr> <td align="left"><input id="fileForSign" maxlength="64" size="50" name="tbFileForSign"></td> </tr> <tr> <td height="3"> </td> </tr> <tr> <td align="right"><input disable="true" value=" " onclick="signFile();" type="button"> </td> </tr> <tr> <td align="right"><textarea id="signature" rows="6" cols="44" name="tbSignatureArea"></textarea> </td> </tr> </tbody> </table> </td></tr></tbody> </table> </td></tr></tbody></table> </td></tr> <!--End top half--> </tbody></table> </tbody></table> </center> </body></html>
      
      






All Articles