logo
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Zloy Strelok  
#1 Оставлено : 1 ноября 2018 г. 8:21:19(UTC)
Zloy Strelok

Статус: Активный участник

Группы: Участники
Зарегистрирован: 06.07.2012(UTC)
Сообщений: 265
Мужчина
Российская Федерация
Откуда: Калининград

Сказал «Спасибо»: 51 раз
Поблагодарили: 30 раз в 22 постах
Добрый день. Пытаюсь на c# через P/Invoke разобрать запрос на сертификат и в итоге получить открытый ключ. По описанию в данной теме (https://www.cryptopro.ru/CryptoPro/forum/view.asp?q=1085), нужно дважды вызвать CryptDecodeObject - сперва получить структуру CERT_SIGNED_CONTENT а потом из нее получить CERT_REQUEST_INFO. Структуру CERT_SIGNED_CONTENT вроде удалось получить, а вот когда проделываю decode для нее, то указатель pcbStructInfo2 остается 0. Может быть я неправильно подаю полученную структуру на вход к CryptDecodeObject? Подскажите, пожалуйста, знающие люди!

Результат в консоли и код прилагаю:

результат в консоли

Код:
public static void Main(string[] args)
		{
			Console.WriteLine("Hello World!");
			
			uint pcbStructInfo = 0;
			
			byte[] raw = Convert.FromBase64String(File.ReadAllText("request.pem"));
			
			CryptDecodeObject(65537,1,raw,raw.Length,0x8,IntPtr.Zero, ref pcbStructInfo);
			
			Console.WriteLine("pcbStructInfo: " + pcbStructInfo);
			
			IntPtr pvStructInfo = Marshal.AllocHGlobal((IntPtr)pcbStructInfo);
			Console.WriteLine("pvStructInfo: " + pvStructInfo);
			
			CryptDecodeObject(65537,1,raw,raw.Length,0x8,pvStructInfo, ref pcbStructInfo);
			
			CERT_SIGNED_CONTENT_INFO str = new CERT_SIGNED_CONTENT_INFO();
			
			str = Marshal.PtrToStructure<CERT_SIGNED_CONTENT_INFO>(pvStructInfo);
			
			Console.WriteLine("str.SignatureAlgorithm.pszObjId: " + str.SignatureAlgorithm.pszObjId);
			
			byte[] raw2 = getBytes(str);
			
			uint pcbStructInfo2 = 0;
			
			CryptDecodeObject(65537,4,raw2,raw2.Length,0x8,IntPtr.Zero, ref pcbStructInfo2);
			
			Console.WriteLine("pcbStructInfo2: " + pcbStructInfo2);
			
			/*
			IntPtr pvStructInfo2 = Marshal.AllocHGlobal((IntPtr)pcbStructInfo2);
			Console.WriteLine(pvStructInfo2);
			
			CERT_REQUEST_INFO str2 = new CERT_REQUEST_INFO();
			
			str = Marshal.PtrToStructure<CERT_SIGNED_CONTENT_INFO>(pvStructInfo2);
			
			Console.WriteLine(str2.SubjectPublicKeyInfo.PublicKey.ToString());
			*/
			
			Console.Write("Press any key to continue . . . ");
			Console.ReadKey(true);
		}
		
		static byte[] getBytes(CERT_SIGNED_CONTENT_INFO str)
		{
			int size = Marshal.SizeOf(str);
			byte[] arr = new byte[size];
			IntPtr ptr = Marshal.AllocHGlobal(size);
			Marshal.StructureToPtr(str, ptr, false);
			Marshal.Copy(ptr, arr, 0, size);
			Marshal.FreeHGlobal(ptr);
			return arr;
		}
		
		[DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]

		internal static extern Boolean CryptDecodeObject(

			UInt32 dwCertEncodingType,

			UInt32 lpszStructType,

			byte[] pbEncoded,

			Int32 cbEncoded,

			UInt32 dwFlags,

			IntPtr pvStructInfo,

			ref UInt32 pcbStructInfo

		);
		
		public struct CERT_SIGNED_CONTENT_INFO {
			public CRYPTOAPI_BLOB ToBeSigned;
			public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
			public CRYPT_BIT_BLOB Signature;
		}
		public struct CRYPTOAPI_BLOB {
			public UInt32 cbData;
			public IntPtr pbData;
		}
		public struct CRYPT_ALGORITHM_IDENTIFIER {
			[MarshalAs(UnmanagedType.LPStr)]
			public String pszObjId;
			public CRYPTOAPI_BLOB Parameters;
		}
		public struct CRYPT_BIT_BLOB {
			public UInt32 cbData;
			public IntPtr pbData;
			public UInt32 cUnusedBits;
		}
		public struct CERT_REQUEST_INFO {
			public uint dwVersion;
			public CRYPTOAPI_BLOB       Subject;
			public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
			public uint cAttribute;
			public CRYPT_ATTRIBUTE rgAttribute;
		}
		public struct CERT_PUBLIC_KEY_INFO {
			public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
			public CRYPT_BIT_BLOB PublicKey;
		}
		public struct CRYPT_ATTRIBUTE {
			public string pszObjId;
			public UInt32 cValue;
			public CRYPTOAPI_BLOB rgValue;
		}
Offline two_oceans  
#2 Оставлено : 2 ноября 2018 г. 9:57:11(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 138
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 8 раз
Поблагодарили: 33 раз в 33 постах
Вроде все так на первый взгляд, с темой на которую ссылка согласуется, хотя не проверял соответствуют ли 1 и 4 значениям X509_CERT и X509_CERT_REQUEST_TO_BE_SIGNED и правильные ли флаги. В закомментированном участке нет еще одного декодирования и тип кажется не исправлен, скопирован с декодирования выше. В принципе можно просто проверить результат CryptDecodeObject: если false вывести результат GetLastError() на консоль, если true выполнить закомментированные действия. По коду ошибки будет яснее что не так при декодировании.

Что бросилось в глаза: 1. в общем случае в pem файле могут быть и посторонние данные, не только запрос. Желательно не читать все целиком, а выделить только содержимое между органичителями запроса. А вот если ограничителей нет - то декодировать все.
2. зачем данные полученной структуры из шага 1 в getBytes куда-то копировать и преобразовать тип? Это лишний шанс испортить данные. Не проще просто сделать второе объявление CryptDecodeObject2, в котором третьим входным параметром сразу будет IntPtr pbEncoded и передать указатель на полученную структуру (pvStructInfo) напрямую. Размер уже получаете как SizeOf(CERT_SIGNED_CONTENT_INFO).
Offline Zloy Strelok  
#3 Оставлено : 6 ноября 2018 г. 7:14:48(UTC)
Zloy Strelok

Статус: Активный участник

Группы: Участники
Зарегистрирован: 06.07.2012(UTC)
Сообщений: 265
Мужчина
Российская Федерация
Откуда: Калининград

Сказал «Спасибо»: 51 раз
Поблагодарили: 30 раз в 22 постах
Автор: two_oceans Перейти к цитате
Вроде все так на первый взгляд, с темой на которую ссылка согласуется, хотя не проверял соответствуют ли 1 и 4 значениям X509_CERT и X509_CERT_REQUEST_TO_BE_SIGNED и правильные ли флаги. В закомментированном участке нет еще одного декодирования и тип кажется не исправлен, скопирован с декодирования выше. В принципе можно просто проверить результат CryptDecodeObject: если false вывести результат GetLastError() на консоль, если true выполнить закомментированные действия. По коду ошибки будет яснее что не так при декодировании.

Что бросилось в глаза: 1. в общем случае в pem файле могут быть и посторонние данные, не только запрос. Желательно не читать все целиком, а выделить только содержимое между органичителями запроса. А вот если ограничителей нет - то декодировать все.
2. зачем данные полученной структуры из шага 1 в getBytes куда-то копировать и преобразовать тип? Это лишний шанс испортить данные. Не проще просто сделать второе объявление CryptDecodeObject2, в котором третьим входным параметром сразу будет IntPtr pbEncoded и передать указатель на полученную структуру (pvStructInfo) напрямую. Размер уже получаете как SizeOf(CERT_SIGNED_CONTENT_INFO).


Спасибо большое! Не ожидал получить такой подробный и развернутый ответ =) Попробую применить советы.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.