Аутентификация на сайтах с помощью Rutoken WEB / Хабр

Аутентификация на  сайтах с помощью Rutoken WEB / Хабр Электронная цифровая подпись

Что нужно из оборудования

  • Компьютер. На нем производится запись необходимого материала с экрана, хранятся все файлы для видео и монтируется ролик.
  • Штатив. На него можно закрепить мобильный телефон для съемки живых кадров.
  • Мобильный телефон. На него, как вы уже догадались, можно снимать живые кадры. Когда есть возможность позвать в этот проект видеооператора, штатив и мобильный телефон не нужны, так как процесс съемки обеспечивает видеооператор.
  • Диктофон. На него записывается звук. Никакой конкретный рекламировать не будем, используйте любой, можно даже тот, что есть в мобильном телефоне.
  • Монтажная программа. В ней мы монтируем и собираем видео. У нас их две: для простого линейного монтажа мы используем программу Movavi, а для более сложного — Adobe Premiere Pro. Первая очень простая и быстрая в освоении. Конечно необходимо, чтобы все используемое ПО было лицензированным.
  • Много памяти на компьютере и мощный процессор. Чтобы сохранять все файлы для ролика и быстро его собирать. Файлы для ролика занимают в разы больше места, чем обычная документация.
  • Программа для обработки звука. В ней мы обрабатываем звук. Можно установить специальную, а можно использовать возможности программы  Adobe Premiere Pro.
  • Текстовый редактор. В нем мы пишем сценарий. Использовать можно любой, но лучше всего тот, в котором организована возможность совместной работы с документом. Например, можно использовать  Microsoft Word 2022 или Google Docs.
  • Программа для записи видео с экрана. С ее помощью мы снимаем видео с экрана, если это необходимо. Мы используем ту же программу, в которой мы делаем скриншоты для обычной документации, это программа Snagit.
  • Программа для создания текстовых слайдов для роликов. Можно использовать любую, мы используем графический онлайн-редактор Readymag.

.

Библитека signature

.

.

int init(
          const char* install_path
);

.

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	/* расширенные способы использования ключа, через , */	
);

.

int save_pem_cert(	
       const char* cert,	               /* сертификат в PEM */		
       const char* cert_file,               /*файл с сертификатом в PEM */		
       const char* slot_cert_id,         /* SLOT : ID сертификата */			
       const char* label                     /* label */	 			
);

.

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-присоединенная */
);

.

.

.

#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

.

#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;	
}

.

Как монтировать ролик

.

.

.

.

.

.

.

.

.

Как снимать видео с экрана компьютера или мобильного устройства

.

.

.

.

.

.

Как снимать реальные кадры или записывать закадровый голос

.

.

.

.

.

.

.

.

.

.

.

.

Кто нужен для производства видеоинструкции

.

.

  • Технический писатель. Тот, который писал инструкцию для нашей смарт-карты. Он уже многое знает и напишет сценарий быстрее, чем любой другой, кому придется разбираться в этой теме. Зачем он нам: написать сценарий и снять видео с экрана своего компьютера. Также, если в видео есть реальные кадры, то нарисовать раскадровку для видеооператора. Это идеальная картина, бывает так, что технический писатель и режиссер, и оператор, и монтажер.
  • Видеооператор. Ему  совсем не обязательно быть в теме, для него создана раскадровка, и он по ней работает. У нас это не всегда отдельный человек, если нет на это ресурсов, то тот, кто пишет сценарий и снимает живые кадры. В этот раз он у нас был. Зачем он нам: качественно снять живые кадры и при необходимости помочь с монтажом.
  • Монтажер. У нас это тот, кто писал сценарий, он собирает весь ролик. Видеооператор может помочь ему выполнить какие-то сложные моменты. В этот раз они были: нам надо было показать одновременную работу смарт-карты в двух мобильных операционных системах.
  • Человек, записывающий закадровый голос. У нас это реальный сотрудник технической поддержки, его голос знаком нашим пользователям. Он записывает закадровый голос для ролика.
Читайте также:  Гайд по внутренней документации по информационной безопасности. Что, как и зачем / Блог компании Информационный центр / Хабр

.

Монтируем созданный том

.

Файл

.

.


Если у Вас не подключен рутокен, то вы получите ошибку «

.

.

image

.

.

.

Обязательно ли писать сценарий

.

.

.

.

.

.

Опыт применения технологии рутокен для регистрации и авторизации пользователей в системе (часть 2)

.

.

).

.

.

.

  1. Скачиваем установочный дистрибутив openssl-1.1.1g.
    У openSSL имеются различные версии. В документации к Рутокену было сказано, что необходима версия openSSL версии 1.1.0 или новее. Я использовал версию openssl-1.1.1g. Можно скачать openSSL с официального сайта, но для более простой установки необходимо найти установочный файл для windows в сети. Я это сделал за вас: slproweb.com/products/Win32OpenSSL.html
    Необходимо пролистать вниз страницы и скачать Win64 OpenSSL v1.1.1g EXE 63MB Installer.
  2. Устанавливаем openssl-1.1.1g на компьютер.
    Установку необходимо провести по стандартному пути, который указывается автоматически в папку C:Program Files. Программа установится в папку OpenSSL-Win64.
  3. Для того, чтобы настроить openSSL так как вам нужно, существует файл openssl.cfg. Этот файл расположен в пути C:Program FilesOpenSSL-Win64bin если вы установили openSSL так, как было сказано в предыдущем пункте. Переходим в папку, где хранится openssl.cfg и открываем этот файл с использованием, например, Notepad .
  4. Вы наверно догадались, что настройка удостоверяющего центра будет производиться как-то изменением содержимого файла openssl.cfg, и вы абсолютно правы. Для этого требуется настроить команду [ ca ]. В файле openssl.cfg начало текста, куда мы будем вносить изменения, можно найти как: [ ca ].
  5. Теперь я приведу пример настройки с его описанием:
    [ ca ]
    default_ca	= CA_default		
    
     [ CA_default ]
    dir		= /Users/username/bin/openSSLca/demoCA		 
    certs		= $dir/certs		
    crl_dir		= $dir/crl		
    database	= $dir/index.txt	
    new_certs_dir	= $dir/newcerts	
    certificate	= $dir/ca.crt 	
    serial		= $dir/private/serial 		
    crlnumber	= $dir/crlnumber	
    					
    crl		= $dir/crl.pem 		
    private_key	= $dir/private/ca.key
    x509_extensions	= usr_cert
    

    .

    .

    .

    .

    .

  6. Подключаем алгоритмы шифрования предоставляемые Рутокеном.
    Это подключение происходит в файле openssl.cfg.
    • Прежде всего требуется скачать необходимые алгоритмы Рутокена. Это файлы rtengine.dll, rtpkcs11ecp.dll.
      Для этого скачиваем Рутокен SDK: www.rutoken.ru/developers/sdk.

      .

      sdk/openssl/rtengine/bin/windows-x86_64/lib/rtengine.dll
      sdk/pkcs11/lib/windows-x86_64/rtpkcs11ecp.dll

      .

    • Библиотеки rtengine.dll и rtpkcs11ecp.dll можно держать в любом месте учетной записи пользователя.
    • Прописываем пути к этим библиотекам в openssl.cfg. Для этого открываем файл openssl.cfg, в начало этого файла необходимо поместить строчку:
      openssl_conf = openssl_def

      .

      [ openssl_def ]
      engines = engine_section
      [ engine_section ]
      rtengine = gost_section
      [ gost_section ]
      dynamic_path = /Users/username/bin/sdk-rutoken/openssl/rtengine/bin/windows-x86_64/lib/rtengine.dll
      MODULE_PATH = /Users/username/bin/sdk-rutoken/pkcs11/lib/windows-x86_64/rtpkcs11ecp.dll
      RAND_TOKEN = pkcs11:manufacturer=Aktiv Co.;model=Rutoken ECP
      default_algorithms = CIPHERS, DIGEST, PKEY, RAND
      

      dynamic_path – необходимо прописать свой путь к библиотеке rtengine.dll.
      MODULE_PATH — необходимо прописать свой путь к библиотеке rtpkcs11ecp.dll.

  7. Добавляем переменные среды.

    .

    .

  8. Теперь можно вернуться к пункту 5 и создать недостающие файлы для каталога demoCA.
    1. Первый важный файл без которого ничего не будет работать — serial. Это файл без расширения, значение которого должно быть 01. Можно создать этот файл самостоятельно и прописать внутрь 01. Также можно скачать его из Рутокен SDK по пути sdk/openssl/rtengine/samples/tool/demoCA/.
      В каталоге demoCA лежит файл serial, который нам как раз и нужен.
    2. Создаем корневой приватный ключ.
      Для этого воспользуемся командой библиотеки openSSL, которую необходимо запустить прямо в командной строке:
      openssl genpkey -algorithm gost2022_256 -pkeyopt paramset:A -out ca.key
    3. Создаем корневой сертификат.
      Для этого воспользуемся следующей командой библиотеки openSSL:
      openssl req -utf8 -x509 -key ca.key -out ca.crt

      Обратите внимание, что для создания корневого сертификата требуется корневой приватный ключ, который создавался на предыдущем шаге. Поэтому командная строка должна быть запущена в одной и той же директории.

    Все теперь имеются все недостающие файлы для полной конфигурации каталога demoCA. Поместите созданные файлы в те каталоги, которые указаны в пункте 5.

.

.

Создаем зашифрованный том

ВНИМАНИЕ! Все дальнейшие необдуманные действия с Вашей стороны со своим жестким диском на Ваш страх и риск! Я описываю самый безопасный способ создания скрытого раздела. Если не хотите потерять данные, придерживайтесь инструкции.Для создания нового тома используем мастер создания томов TrueCrypt – ТомаСоздать новый раздел.
Запускается «Мастер создания томов TrueCrypt». Выбираем «Создать зашифрованный файловый контейнер», т.е. виртуальный зашифрованный диск будет храниться в одной файле.
imageОбычный том».
image
image
image
imageТокен-файлы», вводим пароль рутокена и выбираем токен.
image
image

Оцените статью
ЭЦП Эксперт
Добавить комментарий