Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 12,685 Сказал «Спасибо»: 500 раз Поблагодарили: 2044 раз в 1585 постах
|
Часть переменных - не используется\удалено из примера - почистить.
Код:
szOID_CP_GOST_R3411 = '1.2.643.2.2.9';
szOID_SHA1RSA = '1.2.840.113549.1.1.5';
id_tc26_gost3410_12_256 = '1.2.643.7.1.1.1.1'; //алгоритм подписи ГОСТ Р 34.10-2012 с ключом 256
id_tc26_gost3410_12_512 = '1.2.643.7.1.1.1.2'; //алгоритм подписи ГОСТ Р 34.10-2012 с ключом 512
id_tc26_gost3411_12_256 = '1.2.643.7.1.1.2.2'; //алгоритм хэширования ГОСТ Р 34.11-12 с ключом 256
id_tc26_gost3411_12_512 = '1.2.643.7.1.1.2.3'; //алгоритм хэширования ГОСТ Р 34.11-12 с ключом 512
var
hProv: HCRYPTPROV;
pcoSignerCert: PCCERT_CONTEXT;
CountSigners, j: integer;
Fields: TFieldsCertificate;
SerialNumbers: TStrings;
s: ansistring;
Cert_array_L: integer;
Cert_array: array[0..10] of PCCERT_CONTEXT;
PrivateKey: boolean;
pOidInfo: PCCRYPT_OID_INFO;
SignFileSize: cardinal;
keytype: DWORD;
size: DWORD;
hMsg: HCRYPTMSG;
HashAlgorithm_OID: ansistring;
HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER;
HashAlgSize: DWORD;
coSignerEncodeInfo: CMSG_SIGNER_ENCODE_INFO;
Auth_comment: ansistring;
FTime: TFileTime;
pbAuth: PBYTE;
cbAuth: DWORD;
s_tmp, s_SignUsage, s_IDResource, S_Comment, S_Comment_All, S_Printable, S_Info_CSP, S_Info_App, s_Info_Extensions: ansistring;
cablob: CRYPT_ATTR_BLOB;
dablob: CRYPT_ATTR_BLOB;
Auth_Usage_blob, Auth_IDResourse_blob, Auth_COMMENT_blob, Auth_COMMENT_ALL_blob, Auth_Printable_blob, Auth_Info_CSP, Auth_Info_App, Auth_Info_Extensions: CRYPT_ATTR_BLOB;
ca: array[0..5] of CRYPT_ATTRIBUTE;
coSignerEncodeInfoArray: array[0..0] of CMSG_SIGNER_ENCODE_INFO; // Массив структур, описывающих отправителя
coSignerCertBlob: CERT_BLOB;
CACertBlob: CERT_BLOB;
coSignerCertBlobArray: array[0..10] of CERT_BLOB;
cbEncodedBlob: DWORD;
pbEncodedBlob: pbyte;
SignedMsgEncodeInfo: CMSG_SIGNED_ENCODE_INFO; // Структура, описывающая подписанное сообщение
stStreamInfo: CMSG_STREAM_INFO;
// hOutFile:THandle;
FN_Sign_tmp: AnsiString;
pdwFlags, flags: DWORD;
cbContent: ansistring;
i: word;
line, errors: ansistring;
mem_len: cardinal;
FSign: TMemoryStream;
Sign: TFileStream;
x: integer;
msg, last_result_msg: ansistring;
dt_start: TdateTime;
Buffer: PByte;
len: dWord;
fsIn, fsOut: TFileStream;
isFinal, IsEndOfFile, last_result: Boolean;
// StreamInfo : CMSG_STREAM_INFO;
procedure L(sss: ansistring);
begin
///
end;
//cosign
function EncodeCallBack(const pvArg: Pointer; pbData: PBYTE; cbData: DWORD; fFinal: BOOL): BOOL; stdcall;
var
writtenBytes: Dword;
begin
result := writeFile(cardinal(pvArg^), pbData^, cbData, writtenBytes, nil);
end;
begin
result := -1;
if not FileExists(FN) then
begin
L('Не найден файл ' + FN);
exit;
end;
if not FileExists(FN_Sign) then
begin
L('Не найден файл ' + FN_Sign);
exit;
end;
if checkBefore then
begin
// написать проверку
end;
///////// получение списка серийных номеров сертификатов, уже присутствующих в cms
SerialNumbers := TStringList.Create;
// Get_Certificates_in_pkcs7(FN_Sign, log, resultmsg, nil, Fields, '', SerialNumbers);
if BUF_LEN < 1 then
BUF_LEN := 1024 * 32;
if not assigned(Global_My) then
Global_My := CertOpenSystemStoreA(0, 'MY');
if (not assigned(Global_My)) then
l('Ошибка при открытии хранилища: MY');
if not Find_Certificate(Global_My,
{Cert.SerialNumber}'', Cert.Thumbprint, pcoSignerCert, resultmsg) then
begin
l(Format('Сертификат %s не доступен', [Cert.SerialNumber]) + ' ' + resultmsg);
exit;
end;
if (not assigned(pcoSignerCert)) then
l(Format('Сертификат %s не найден', [Cert.SerialNumber]));
PrivateKey := CryptAcquireCertificatePrivateKey(pcoSignerCert, 0, nil, hProv, @keytype, nil);
L('Закрытый ключ [keytype=' + IntToStr(keytype) + '] [' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror()));
if not PrivateKey then
begin
resultmsg := 'Нет доступа к закрытому ключу. ';
l(resultmsg);
result := -4;
exit;
end;
////////////////////////////////////////////////////////////////////////////////////////////////////////
pOidInfo := CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pcoSignerCert^.pCertInfo^.SignatureAlgorithm.pszObjId, CRYPT_SIGN_ALG_OID_GROUP_ID);
if assigned(pOidInfo) then
begin
L('Алгоритм подписи сертификата: ' + pOidInfo^.pwszName + ' OID: ' + pOidInfo^.pszOID);
end;
////////////////////////////////////////////////////////////////////////////////////////////////////////
pOidInfo := CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pcoSignerCert^.pCertInfo^.SubjectPublicKeyInfo.Algorithm.pszObjId, CRYPT_PUBKEY_ALG_OID_GROUP_ID);
HashAlgorithm_OID := szOID_CP_GOST_R3411;
if assigned(pOidInfo) then
begin
L('Открытый ключ сертификата: ' + pOidInfo^.pwszName + ' OID: ' + pOidInfo^.pszOID);
if pos('.643.', pOidInfo^.pszOID) <> 0 then
begin
HashAlgorithm_OID := szOID_CP_GOST_R3411;
//todo gost 2012
if pOidInfo^.pszOID = id_tc26_gost3410_12_256 then
HashAlgorithm_OID := id_tc26_gost3411_12_256;
if pOidInfo^.pszOID = id_tc26_gost3410_12_512 then
HashAlgorithm_OID := id_tc26_gost3411_12_512;
end
else
HashAlgorithm_OID := szOID_SHA1RSA;
end;
errors := '';
dt_start := now;
// --------------------------------------------------------------------
// Инициализируем структуру алгоритма
ZeroMemory(@HashAlgorithm, SizeOf(HashAlgorithm));
HashAlgorithm.pszObjId := PAnsiChar(HashAlgorithm_OID); // Идентификатор алгоритма хэша
L('Алгоритм хеширования: ' + HashAlgorithm.pszObjId);
// Инициализируем структуру CMSG_SIGNER_ENCODE_INFO
ZeroMemory(@coSignerEncodeInfo, SizeOf(CMSG_SIGNER_ENCODE_INFO));
coSignerEncodeInfo.cbSize := sizeof(CMSG_SIGNER_ENCODE_INFO);
coSignerEncodeInfo.HashAlgorithm := HashAlgorithm;
coSignerEncodeInfo.HashAlgorithm.pszObjId := PAnsiChar(HashAlgorithm_OID);
coSignerEncodeInfo.pCertInfo := pcoSignerCert.pCertInfo;
coSignerEncodeInfo.hCryptProv := hProv;
coSignerEncodeInfo.dwKeySpec := keytype; //AT_KEYEXCHANGE;
coSignerEncodeInfo.pvHashAuxInfo := nil;
FTime := DateTimeToFileTime(DT_Sign);
CryptEncodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime, @FTime, nil, cbAuth);
GetMem(pbAuth, cbAuth);
CryptEncodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime, @FTime, pbAuth, cbAuth);
L('Дата и время [' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror()));
cablob {[0]}.cbData := cbAuth;
cablob.pbData := pbAuth;
ca[0].pszObjId := szOID_RSA_signingTime;
ca[0].cValue := 1;
ca[0].rgValue := @cablob;
coSignerEncodeInfo.cAuthAttr := 1; //time
coSignerEncodeInfo.rgAuthAttr := @ca;
L('Соподпись. Добавлены атрибуты [' + IntToStr(coSignerEncodeInfo.cAuthAttr) + ']');
// --------------------------------------------------------------------
// Создадим массив отправителей. Сейчас только из одного.
// setlength(SignerEncodeInfoArray,1);
coSignerEncodeInfoArray[0] := coSignerEncodeInfo;
// --------------------------------------------------------------------
// Инициализируем структуру CMSG_SIGNED_ENCODE_INFO
coSignerCertBlob.cbData := pcoSignerCert.cbCertEncoded;
coSignerCertBlob.pbData := pcoSignerCert.pbCertEncoded;
// L(' Cert ['+IntToStr(getlasterror())+']: '+syserrormessage(getlasterror()));
// setlength(SignerCertBlobArray,1);
coSignerCertBlobArray[0] := coSignerCertBlob;
// --------------------------------------------------------------------
// Инициализируем структуру массив структур CertBlob.
ZeroMemory(@SignedMsgEncodeInfo, SizeOf(CMSG_SIGNED_ENCODE_INFO));
// FillChar( SignedMsgEncodeInfo, SizeOf( CMSG_SIGNED_ENCODE_INFO ), #0 );
SignedMsgEncodeInfo.cbSize := sizeof(CMSG_SIGNED_ENCODE_INFO);
SignedMsgEncodeInfo.cSigners := 1; //1
SignedMsgEncodeInfo.rgSigners := @coSignerEncodeInfoArray;
if not assigned(Global_CAStore) then
Global_CAStore := CertOpenSystemStoreA(0, 'CA');
if not assigned(Global_RootStore) then
Global_RootStore := CertOpenSystemStoreA(0, 'ROOT');
Cert_array[0] := pcoSignerCert; // сертификат пользователя
if assigned(Cert_array[0]) then
for j := 1 to 10 do
begin // поиск сертификатов ЦР\УЦ
L('@поиск сертификата CA\ROOT: [' + IntToStr(j) + ']');
Cert_array_L := j;
Cert_array[j] := //old Get_IssuerCert(rootStore,CAStore,Cert_array[j-1], log);
Find_CertificateInStore(Cert_array[j - 1], Global_rootStore, Global_CAStore, msg, x);
L('x=[' + IntToStr(x) + '] msg=>' + msg);
if not assigned(Cert_array[j]) then
begin // не найден => значит текущий = ROOT (если цепочка корректна и установлены сертификаты)
break;
end;
end;
L('@сертификаты: [' + IntToStr(Cert_array_L) + ']');
//SignedMsgEncodeInfo.cCertEncoded := 1;
SignedMsgEncodeInfo.cCertEncoded := Cert_array_L;
L('Cert_array = [' + IntToStr(SignedMsgEncodeInfo.cCertEncoded) + ']');
for j := low(Cert_array) to high(Cert_array) do
begin
if not assigned(Cert_array[j]) then
break;
coSignerCertBlobArray[j].cbData := Cert_array[j].cbCertEncoded;
coSignerCertBlobArray[j].pbData := Cert_array[j].pbCertEncoded;
L('Сертификат[' + IntToStr(j + 1) + '] Номер:' + Bin2HexReverse(Cert_array[j].pCertInfo.SerialNumber));
end;
SignedMsgEncodeInfo.rgCertEncoded := @coSignerCertBlobArray;
SignedMsgEncodeInfo.rgCrlEncoded := nil;
SignedMsgEncodeInfo.cCrlEncoded := 0;
flags := CMSG_DETACHED_FLAG;
// --------------------------------------------------------------------
mem_len := FSize(FN);
L('Алгоритм хеширования: ' + HashAlgorithm.pszObjId);
flags := 0;
if DetachedSig then
flags := CMSG_DETACHED_FLAG;
hMsg := CryptMsgOpenToDecode(MY_ENCODING_TYPE, // Encoding type
flags, //CMSG_DETACHED_FLAG,// flags, // Flags (CMSG_DETACHED_FLAG)
0, // CMSG_SIGNED, // Message type
0, //@SignedMsgEncodeInfo, // Pointer to structure
nil, // Inner content object ID
nil //@stStreamInfo // Stream information (not used)
);
if DetachedSig then
begin
SignFileSize := FSize(FN_Sign);
fsIn := TFileStream.Create(FN_Sign, fmOpenRead or fmShareDenyWrite);
GetMem(Buffer, SignFileSize);
len := fsIn.Read(Buffer^, SignFileSize);
CryptMsgUpdate(hMsg, Buffer, len, true); // if not ... // todo!
L('Обновление памяти [' + IntToStr(SignFileSize) + '] err=[' + IntToStr(getlasterror()) + '] size=[' + IntToStr(size) + ']:' + syserrormessage(getlasterror()));
FreeMem(Buffer, SignFileSize);
fsIn.Free;
end;
fsIn := TFileStream.Create(FN, fmOpenRead or fmShareDenyWrite);
last_result := false;
try
{allocate buffer to read content from source file}
GetMem(Buffer, BUF_LEN);
repeat
IsEndOfFile := (fsIn.Position >= fsIn.Size);
Wait.percent := round((100 * fsIn.Position) / fsIn.Size);
if Wait.percent > 100 then
Wait.percent := 100;
Wait.FncWait(Wait.percent);
if IsEndOfFile then
begin
// CryptMsgUpdate(hMsg, Buffer, len, true);
L('Stream.end'); //err=['+IntToStr(getlasterror())+'] size=['+IntToStr(size)+']:'+syserrormessage(getlasterror()));
break;
end;
{read content from source file}
len := fsIn.Read(Buffer^, BUF_LEN);
if len < BUF_LEN then
begin
last_result := CryptMsgUpdate(hMsg, Buffer, len, true);
last_result_msg := 'Код ошибки: ' + IntToStr(getlasterror()) + ' - ' + syserrormessage(getlasterror());
L('Последний блок.[' + IntToStr(getlasterror()) + '] len=[' + IntToStr(len) + ']:' + syserrormessage(getlasterror()));
end;
if len = BUF_LEN then
begin
isFinal := false;
if fsIn.Position = fsIn.Size then
isFinal := true;
last_result := CryptMsgUpdate(hMsg, Buffer, len, isFinal);
last_result_msg := 'Код ошибки: ' + IntToStr(getlasterror()) + ' - ' + syserrormessage(getlasterror());
end;
until IsEndOfFile;
FreeMem(Buffer, BUF_LEN);
finally
fsIn.Free;
end;
if not CryptMsgControl(hMsg, 0, // flags,
CMSG_CTRL_ADD_SIGNER, @coSignerEncodeInfo) then
begin
L('Error: CryptMsgControl ADD_SIGNER [' + IntToStr(getlasterror()) + '] :' + syserrormessage(getlasterror()));
resultmsg := 'Ошибка при создании дополнительной подписи: ' + IntToStr(getlasterror()) + ' - ' + syserrormessage(getlasterror());
result := -1; // add path 20171116 05:15
exit;
end;
for j := low(Cert_array) to high(Cert_array) do
begin
if not assigned(Cert_array[j]) then
break;
s := Bin2HexReverse(Cert_array[j].pCertInfo.SerialNumber);
if pos(s, SerialNumbers.Text) <> 0 then
begin
L('Пропуск сертификата [' + IntToStr(j + 1) + ']:' + s + ' уже присутствует в наборе');
continue;
end;
if not CryptMsgControl(hMsg, 0, // flags,
CMSG_CTRL_ADD_CERT, @coSignerCertBlobArray[j]) then
begin
L('Error: CryptMsgControl ADD_CERT[' + IntToStr(j) + '] [' + IntToStr(getlasterror()) + '] :' + syserrormessage(getlasterror()));
exit;
end;
L('Добавление Сертификата [' + IntToStr(j + 1) + '] Номер:' + s);
end;
if assigned(SerialNumbers) then
FreeAndNil(SerialNumbers);
if (CryptMsgGetParam(hMsg, // Handle to the message
CMSG_ENCODED_MESSAGE, //
// CMSG_CONTENT_PARAM, // исходник Parameter type
0, // Index
nil, // Pointer to the blob
cbEncodedBlob) // Size of the blob
) then
errors := errors + 'ЭП создана'
else
begin
errors := errors + 'ЭП не создана';
last_result := false;
last_result_msg := 'Ошибка CryptMsgGetParam [' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror());
end;
L(' Param1 cb Blob=[' + IntToStr(cbEncodedBlob) + '][' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror()));
GetMem(pbEncodedBlob, cbEncodedBlob);
if (CryptMsgGetParam(hMsg, // Handle to the message
CMSG_ENCODED_MESSAGE, // CMSG_CONTENT_PARAM, // Parameter type
// CMSG_CONTENT_PARAM,// исходник
0, // Index
pbEncodedBlob, // Pointer to the blob
cbEncodedBlob) // Size of the blob
) then
begin
L('@CryptMsgGetParam[' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror()));
errors := errors + ' Сообщение закодировано'
end
else
begin
L('@CryptMsgGetParam Error[' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror()));
errors := errors + ' Сбой получения параметров';
last_result := false;
last_result_msg := 'Ошибка CryptMsgGetParam [' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror());
end;
L('[' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror()));
L('Размер информации[' + IntToStr(cbEncodedBlob) + ']');
deletefile(FN_Sign);
fsOut := TFileStream.Create(FN_Sign, fmCreate);
fsOut.Write(pbEncodedBlob^, cbEncodedBlob);
L('Запись данных [' + IntToStr(cbEncodedBlob) + '][' + IntToStr(getlasterror()) + ']: ' + syserrormessage(getlasterror()));
fsOut.Free;
if cbEncodedBlob > 0 then
if last_result then
begin
result := 0;
end;
if assigned(hMsg) then
cryptMsgClose(hMsg);
if (hProv) > 0 then
begin
try
CryptReleaseContext(hProv, 0);
except
end;
// hProv := 0;
end;
if not last_result then
begin
result := -1;
resultmsg := last_result_msg;
end;
L(errors);
mem_len := FSize(FN_Sign);
L('Размер файла coSign:' + IntToStr(mem_len));
L('продолжительность: ' + formatdatetime('hh:mm:ss.zzz', now - dt_start));
if mem_len > 10 then
if last_result then
result := 0; //
if assigned(pcoSignerCert) then
CertFreeCertificateContext(pcoSignerCert);
pcoSignerCert := nil;
for j := 0 to 10 do
begin
if assigned(Cert_array[j]) then
begin
Cert_array[j] := nil;
end;
end;
FreeMem(pbAuth);
if assigned(pbEncodedBlob) then
freemem(pbEncodedBlob, cbEncodedBlob);
pbEncodedBlob := nil;
Buffer := nil;
if assigned(SerialNumbers) then
FreeAndNil(SerialNumbers);
end;
|