Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход. Новые регистрации запрещены.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline informatik  
#1 Оставлено : 7 февраля 2012 г. 19:18:45(UTC)
informatik

Статус: Новичок

Группы: Участники
Зарегистрирован: 26.12.2008(UTC)
Сообщений: 5

Поблагодарили: 1 раз в 1 постах
Всем привет.
Очень нужна помощь.
Есть код на C# для верификации подписи с использование CryptoApi и получением ключа из сертификата КриптоПро.

//Считываем сертификат из файла
FileInfo fi = new FileInfo(certPath);
uint certLen;
byte[] cert = new byte[fi.Length];
using (FileStream fs = File.OpenRead(certPath))
{
certLen = (uint)fs.Read(cert, 0, (int)fi.Length);
fs.Close();
}

//Получение контекста публичного сертификата
hCertContext = CryptoApi.CertCreateCertificateContext((int)CryptoPro.CERT_ENCODING, cert, cert.Length);

//Получение контекста криптопровайдера для проверки подписи
CryptoApi.CryptAcquireContext(out hCryptoProvider, null, null, CryptoPro.PROV_GOST_2001_DH, CryptoApi.CRYPT_VERIFYCONTEXT);

//Получаем указатель на SubjectPublicKeyInfo
CryptoApi.CERT_CONTEXT certContextStruct = (CryptoApi.CERT_CONTEXT)Marshal.PtrToStructure(hCertContext,typeof(CryptoApi.CERT_CONTEXT));
IntPtr pCertInfo = certContextStruct.pCertInfo;
IntPtr pSubjectPublicKeyInfo = (IntPtr)(pCertInfo.ToInt32() + 56);

//Импорт публичного ключа в криптопровайдер
CryptoApi.CryptImportPublicKeyInfo(hCryptoProvider, CryptoPro.CERT_ENCODING, pSubjectPublicKeyInfo, out hPubKey); //Вот в этом месте проблема

bool res = CryptoApi.CryptCreateHash(hCryptoProvider, CryptoPro.CALG_GR3411, IntPtr.Zero, 0, ref hHash);

Encoding encoding = Encoding.GetEncoding(encodingHeaderName);
byte[] buffer = encoding.GetBytes(body);

res = CryptoApi.CryptHashData(hHash, buffer, (uint)buffer.Length, 0);

byte[] verifySignature = Convert.FromBase64String(signature);

retVal = CryptoApi.CryptVerifySignature(hHash,verifySignature,verifySignature.Length, hPubKey, null, 0);

Данный код отлично работает на .NET 1.1 независимо от архитектуры операционной системы (x86, x64), наверно потому что .net 1.1 может быть только x86.
Так же отлично работает на NET 4.0 в x86 среде.
Но, при запуске данного кода в приложении .NET 4 под Windows x64 не отрабатывает вызов CryptImportPublicKeyInfo, LastWin32Error = -2146881269 (CRYPT_E_ASN1_BADTAG), ну и соответственно проверка подписи далее не проходит.
Нагуглить решение не смог.

В чем может быть проблема?

Update:
Система: Windows Server 2008 R2
Крипто Про CSP 3.6 KC1

Отредактировано пользователем 7 февраля 2012 г. 19:40:51(UTC)  | Причина: Не указана

Offline Kirill Sobolev  
#2 Оставлено : 7 февраля 2012 г. 20:37:48(UTC)
Кирилл Соболев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,733
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 177 раз в 168 постах
Возможно в этом?
Код:
IntPtr pSubjectPublicKeyInfo = (IntPtr)(pCertInfo.ToInt32() + 56);

Сравните размеры полей под х86 и х64 - в обоих случаях смещение 56?
Техническую поддержку оказываем тут
Наша база знаний
Offline informatik  
#3 Оставлено : 8 февраля 2012 г. 17:50:23(UTC)
informatik

Статус: Новичок

Группы: Участники
Зарегистрирован: 26.12.2008(UTC)
Сообщений: 5

Поблагодарили: 1 раз в 1 постах
Цитата:
Возможно в этом?
Code:
IntPtr pSubjectPublicKeyInfo = (IntPtr)(pCertInfo.ToInt32() + 56);

Сравните размеры полей под х86 и х64 - в обоих случаях смещение 56?


Изначально обращал на это внимание, потом видимо просто откатился на этот вариант, текущее смещение явно будет другим в x64.
Изначально даже получение CertInfo было тоже неверным для x64;
Код:
(IntPtr)Marshal.ReadInt32(hCertContext, 12)


Переделал вот так:
Код:
CryptoApi.CERT_CONTEXT certContextStruct = (CryptoApi.CERT_CONTEXT)Marshal.PtrToStructure(hCertContext,typeof(CryptoApi.CERT_CONTEXT));
IntPtr pCertInfo = certContextStruct.pCertInfo;


Соответственно пытался подобным образом получить ссылку на SubjectPublicKeyInfo:
Код:
win32.CERT_INFO certInfoStruct = (win32.CERT_INFO)Marshal.PtrToStructure(pCertInfo,typeof(win32.CERT_INFO));
IntPtr SubjectPublicKeyInfo = Marshal.AllocHGlobal(Marshal.SizeOf(certInfoStruct.SubjectPublicKeyInfo));
Marshal.StructureToPtr(certInfoStruct.SubjectPublicKeyInfo, SubjectPublicKeyInfo, false);


Т.е. из указателя CertInfo получал структуру и далее пытался получить указатель на поле certInfoStruct.SubjectPublicKeyInfo, чтобы отправить его в CryptImportPublicKeyInfo.
После отправки полученного таким образом указателя в CryptImportPublicKeyInfo на x86 тоже не работает, ошибка -2146893792

Понял что основное отличие в размере IntPtr на разных архитектурах.
Нашел инфу о возможных проблемах http://msdn.microsoft.co...241064%28v=vs.90%29.aspx и миграции неуправляемого кода на x64 http://msdn.microsoft.com/ru-ru/library/ms973190
В общем пробовал уже всяко, пытался высчитать нужное смещение, ничего не получилось.





Offline Kirill Sobolev  
#4 Оставлено : 8 февраля 2012 г. 19:05:40(UTC)
Кирилл Соболев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,733
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 177 раз в 168 постах
Посмотрите, что находится в certInfoStruct.SubjectPublicKeyInfo после win32.CERT_INFO certInfoStruct = (win32.CERT_INFO)Marshal.PtrToStructure(pCertInfo,typeof(win32.CERT_INFO)); - нормальные данные или мусор?
Техническую поддержку оказываем тут
Наша база знаний
Offline informatik  
#5 Оставлено : 9 февраля 2012 г. 11:19:18(UTC)
informatik

Статус: Новичок

Группы: Участники
Зарегистрирован: 26.12.2008(UTC)
Сообщений: 5

Поблагодарили: 1 раз в 1 постах
Цитата:
Посмотрите, что находится в certInfoStruct.SubjectPublicKeyInfo после win32.CERT_INFO certInfoStruct = (win32.CERT_INFO)Marshal.PtrToStructure(pCertInfo,typeof(win32.CERT_INFO)); - нормальные данные или мусор?


По моему получаемая структура вполне нормальна.
Из читаемых напрямую параметров поле pszObjId идентификатора алгоритма = 1.2.643.2.2.19, что соответствует ГОСТ 34.10-2001.
BLOB данные есть но декодировать не пробовал.

Вот объявление структур:

Код:

[StructLayout(LayoutKind.Sequential)]
internal struct CERT_PUBLIC_KEY_INFO
{
	public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
	public CRYPT_BIT_BLOB PublicKey;
}

[StructLayout(LayoutKind.Sequential)]
public struct CERT_CONTEXT  
{
	public uint dwCertEncodingType;
	public IntPtr pbCertEncoded;
	public uint cbCertEncoded;
	public IntPtr pCertInfo;
	public IntPtr hCertStore;
}


[StructLayout(LayoutKind.Sequential)]
public struct CRYPTOAPI_BLOB //x86 - 8, x64 - 16
{
	public Int32 cbData;
	public IntPtr pbData;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CRYPT_OBJID_BLOB //8
{
	public Int32 cbData;
	[MarshalAs(UnmanagedType.ByValArray)]
	public byte[] pbData;
}


[StructLayout(LayoutKind.Sequential)]
internal struct CERT_INFO  
{
	public uint dwVersion; //4
	public CRYPTOAPI_BLOB SerialNumber; //8 - 16
    public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; //12 - 16
	public CRYPTOAPI_BLOB Issuer; //8 - 16
	public System.Runtime.InteropServices.ComTypes.FILETIME NotBefore; //8
    public System.Runtime.InteropServices.ComTypes.FILETIME NotAfter; //8
	public CRYPTOAPI_BLOB Subject; //8 - 16
	public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;//24 - 40
	public CRYPT_BIT_BLOB IssuerUniqueId;//12 - 24
	public CRYPT_BIT_BLOB SubjectUniqueId;//12 - 24
	public uint cExtension;//4
    public IntPtr rgExtension;//4 - 8
}

[StructLayout(LayoutKind.Sequential)]
	internal struct CRYPT_ALGORITHM_IDENTIFIER //12 - 16
{
	[MarshalAs(UnmanagedType.LPStr)]
	public String pszObjId; //4
    public CRYPT_OBJID_BLOB Parameters;//8
}

[StructLayout(LayoutKind.Sequential)]
	internal struct CRYPT_BIT_BLOB //12-24
{
	public Int32 cbData; //4
	public IntPtr pbData;//4-8
    public Int32 cUnusedBits;//4
}
Offline informatik  
#6 Оставлено : 9 февраля 2012 г. 11:52:04(UTC)
informatik

Статус: Новичок

Группы: Участники
Зарегистрирован: 26.12.2008(UTC)
Сообщений: 5

Поблагодарили: 1 раз в 1 постах
Яхууу!!! Все получилось!

Все же маршалинг структуры SubjectPublicKeyInfo был неверный.

Пригляделся к описанию структуры CRYPT_OBJID_BLOB
В MSDN сказано что pbData - A pointer to the data buffer.

Старое объявление:
Код:

 [StructLayout(LayoutKind.Sequential)]
        public struct CRYPT_OBJID_BLOB //8
        {
            public Int32 cbData;
            [MarshalAs(UnmanagedType.ByValArray)]
            public byte[] pbData;
        }


Не помню откуда взял такое объявление...

Заменил CRYPT_OBJID_BLOB на объявленный у меня CRYPTOAPI_BLOB

Код:

[StructLayout(LayoutKind.Sequential,CharSet = CharSet.Unicode)]
	         internal struct CRYPT_ALGORITHM_IDENTIFIER 
		{
			[MarshalAs(UnmanagedType.LPStr)]
			public String pszObjId;
                         public CRYPTOAPI_BLOB Parameters;
		}


Теперь код получения указателя на SubjectPublicKeyInfo работает на разных архитектурах:
Код:
win32.CERT_INFO certInfoStruct = (win32.CERT_INFO)Marshal.PtrToStructure(pCertInfo,typeof(win32.CERT_INFO));
IntPtr SubjectPublicKeyInfo = Marshal.AllocHGlobal(Marshal.SizeOf(certInfoStruct.SubjectPublicKeyInfo));
Marshal.StructureToPtr(certInfoStruct.SubjectPublicKeyInfo, SubjectPublicKeyInfo, false);



Спасибо за помощь Kirill Sobolev!
thanks 1 пользователь поблагодарил informatik за этот пост.
EgorOkhotin оставлено 03.07.2019(UTC)
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.