Пример исходного кода на C

Данный код предназначен для иллюстрации проверки подписи c использованием библиотеки openssl. Подробная документация по установке и использованию библиотеки и утлилит openssl доступна на web-сайте http://www.openssl.org

Компиляция и запуск примера:

  1. Установите библиотеку и утилиты openssl
  2. Загрузите и сохраните в файл eport.cer сертификат публичного ключа ЭЦП e-port по ссылке:
    https://dealer.e-port.ru/cp/ca?cert=1
  3. Создайте файл verify.c, в который разместите исходный код примера
  4. Компиляция и запуск примера для платформы UNIX
    1. Скомпилируйте программу командой
      cc -lcrypto -o ./verify ./verify.c
    2. Запустите программу verify из той директории, где расположен файл ключа.
  5. Компиляция и запуск примера для платформы WINDOWS
    1. Запустите MS Visual Studio, затем выберите пункт меню Tools >> Visual Studio 2005 Command Prompt, в открывшемся окне интерпретатора командной строки перейдите в директорию, где хранится файл с примером.
    2. Скомпилируйте программу командой
      cl -I./inc32 ./verify.c /MD /link ./bin/libeay32.lib ./bin/ssleay32.lib
      при этом вместо ./inc32 укажите путь до директории с заголовочными файлами, поставляемыми в дистрибутиве openssl, вместо ./bin/libeay32.lib и ./bin/ssleay32.lib - пути (вместе с именами) к библиотекам libeay32.lib и ssleay32.lib (эти библиотеки создаются при установке openssl)
    3. Запустите программу verify.exe из той директории, где расположен файл ключа, при этом убедитесь, что путь к библиотекам libeay32.dll и ssleay32.dll присутствует в переменной окружения PATH, либо эти библиотеки находятся в одной директории с программой. Данные библиотеки установливаются вместе с openssl.
    4. При компиляции данного примера использовались openssl версии 0.9.71, компилятор Microsoft C++ из среды разработки Microsoft Visual Studio 2005, пример линковался с использованием msvcrt.lib, т.е. runtime, компилирование и линковка выполнялись в Microsoft Visual Studio 2005 Command Prompt.


#include <stdio.h>
#include <openssl/pem.h>
#include <openssl/evp.h>

int main(int argc, char ** argv){
	// путь к файлу сертификата ЭЦП e-port
	char *path = "eport.cer";
	// подписанные  данные
	char *data  = "test";
	int dlen = 4;
	// подпись e-port в шестнадцатеричном представлении
	char * hex = "6eb9a0485b7b8dc2f8a8ea15760e3d4bd0e4819b7d5703f69a76818015ff20f89ecd07db1813d57ac3181f4f7dfa326bab704d09be2651c88b2bc571fd40d47e5d3abba81ce5e05db68ae7b37100a46f49b5b8846b166f86d5df23b3b38e98dcb5c00aa3c27d8c8ae241911b01a721cb6c32d8104d0989566a51cf91685d14a3";
	// данные подписи для проверки
	unsigned char * sign;
	int slen;
	
	int i, j;
	char c;
	unsigned char h;
	
	FILE * f;
	X509 *cert;
	EVP_MD *md;
	EVP_PKEY *key;
	EVP_MD_CTX *mdctx;
	
	// читаем файл сертификата публичного ключа e-port
	f = fopen("eport.cer", "r");
	if(f == NULL){
		printf("невозможно открыть файл ключа\n");
		return -1;
	}
	cert = PEM_read_X509(f,NULL,NULL,NULL);
	if(cert == NULL)  goto ERROR;
	fclose(f);

	// извлекаем публичный ключ ЭЦП e-port
	key = X509_get_pubkey(cert);
	if(key == NULL)  goto ERROR;

	// определяем размер ключа
	slen = EVP_PKEY_size(key);
	
	// размер подписи будет таким же 
	sign = (unsigned char*) malloc(slen);
	if(sign == NULL) goto ERROR;
		
	// получаем данные подписи из шестнадцатеричного предстваления
	for(i = 0, j = 0; i < slen; i++){
		c = hex[j++];
		if (c > 47 && c < 58) h = c - 48;
		else if (c > 96 && c < 103) h = c - 87;
		else if (c > 64 && c < 71)  h = c - 55;
		else return -1;
		h = h << 4;
		c = hex[j++];
		if (c > 47 && c < 58) h = h | (c - 48);
		else if (c > 96 && c < 103) h = h | (c - 87);
		else if (c > 64 && c < 71)  h = h | (c - 55);
		else return -1;
		sign[i] = h;
	}
	
	// получаем доступ к хэш-функции MD5
	OpenSSL_add_all_digests();
	md  = (EVP_MD*)EVP_get_digestbyname("MD5");
	if(md == NULL) goto ERROR;

	// формируем контекст подписи
	mdctx = EVP_MD_CTX_create();
	if(mdctx == NULL) goto ERROR;
	
	// устанавливаем хэш-функцию, которая буддет использована
	if(! EVP_VerifyInit(mdctx, md))  goto ERROR;
		
	// инициализируем контекст подписанными данными
	if(! EVP_VerifyUpdate(mdctx, data, dlen)) goto ERROR;

	// проверяем полдпись:
	switch(EVP_VerifyFinal (mdctx, sign, slen, key)){
		case 1:
			// подпись верна
			printf("Verify OK\n");
			break;
		case 0:
			// подпись неверна
			printf("Bad signature\n");
			break;
		default:
			// сбой
			goto ERROR;
	}
	free(sign);
	X509_free(cert);
	EVP_PKEY_free(key);
	EVP_MD_CTX_destroy(mdctx);
	
	return 0;
	// отладочная информация при сбое
	ERROR:
	ERR_load_crypto_strings();
	printf("ERROR: %s\n", ERR_error_string(ERR_get_error(),NULL));
	return -1;	

}