Имя: Пароль:
1C
1С v8
Доступ к хранилищу сертификатов ЭП из сеанса под IIS
0 Gleb K
 
26.07.16
10:30
win2008r2 + 1С 8.3 + IIS
Имею http-сервис опубликованный на IIS, необходимо работать с ЭП (проверять подпись запроса и формировать подпись для ответа).

Пул приложений 1С в ISS стартует под собственным пользователем IIS APPPOOL 1C.

Свой сертификат RSA с закрытым ключом установил в хранилище компьютера\личные, дал полные права доступа к нему пользователю IIS APPPOOL 1C (пробовал как через mmc, так и через утилиту winhttpcertcfg). Также пробовал ставить сертификат в хранилище пользователя\личные.

Следующий код не видит сертификата:

МК = Новый МенеджерКриптографии("Microsoft Enhanced Cryptographic Provider v1.0","",1);
//здесь пробовал хранилище и компьютера и пользователя
ХранилищеСертификатов = МК.ПолучитьХранилищеСертификатов();

//Не видит как в лоб
Сертификат = ХранилищеСертификатов.НайтиПоОтпечатку(Base64Значение("a624b6ae158e677113d2fce3e66e332a342e0a87"));

//так и в общем
Сертификат = ХранилищеСертификатов2.ПолучитьВсе();
    
Также пробовал стартовать пул приложений 1С под учеткой Network service и под своей личной учеткой - не помагает.

Если запустить толстый клиент на этой машине, то сертификат видится без проблем.

Ребята, есть идеи?
1 Gleb K
 
26.07.16
16:48
Ап.
2 igork1966
 
26.07.16
17:15
Полагаю что ветка реестра "хранилище компьютера\личные"
не видна под другим пользователем, не?
3 Gleb K
 
26.07.16
23:43
(2) если имеется в виду
HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates
и
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates

То доступ с наследованием на обе ветки проставил, сертификат все равно не видит.
4 Gleb K
 
27.07.16
00:51
(2) Если смотреть через толстый клиент, то текущему пользователю доступно только хранилище пользователя и сертификат виден, а на хранилище компа выдается ошибка, но если на его ветку в реестре добавить права текущему пользователю и поместить туда сертификат, то ошибки не появляется, но ни одного сертификата в этом хранилище не видно.

Поставил сертификат в хранилище пользователя, сделал запуск пула приложений от имени текущего пользователя, сертификаты хранилища пользователя все-равно не видны.
5 Gleb K
 
27.07.16
17:21
Up
6 Aloex
 
27.07.16
17:24
С местом исполнения не ошибся: клиент-сервер?
7 Gleb K
 
27.07.16
17:27
(6) http-сервис вроде исполняется на сервере, при этом используются синхронные вызовы методов, так что вроде контекст правильный.
8 Aloex
 
27.07.16
17:35
ну а толстый клиент на клиенте работает.
9 Gleb K
 
27.07.16
17:41
Да, с толстым все ок.
10 Gleb K
 
27.07.16
23:08
Ап
11 Gleb K
 
28.07.16
10:28
Попробовал через CAPICOM, он видит сертификаты, но при попытке подписать (последняя строка в коде) валится с ошибкой "Ошибка при вызове метода контекста (Sign): Произошла исключительная ситуация: Набор ключей не существует". Пул приложений 1С сейчас стартует под локальным пользователем. Этот же код, но в толстом клиенте под локальным пользователем работает без проблем.

// CAPICOM constants
CAPICOM_LOCAL_MACHINE_STORE = 1;
CAPICOM_CURRENT_USER_STORE=2;
CAPICOM_MY_STORE="My";
CAPICOM_OTHER_STORE="AddressBook";
CAPICOM_STORE_OPEN_READ_ONLY=0;
CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
CAPICOM_CERTIFICATE_FIND_TIME_VALID=9;
CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY = 2;
CAPICOM_ENCODE_BASE64 = 0;
CAPICOM_ENCODE_BINARY = 1;
    
//Найдем сертификат в хранилище
Store = Новый COMОбъект("CAPICOM.Store");
    Store.Open(CAPICOM_LOCAL_MACHINE_STORE,CAPICOM_MY_STORE,CAPICOM_STORE_OPEN_READ_ONLY);
Certificate = Store.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH,"A624B6AE158E677113D2FCE3E66E332A342E0A87").item(1);
    
//Инициализируем подписанта
Signer = Новый COMОбъект("CAPICOM.Signer");
Signer.Certificate = Certificate;
Signer.Options = CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY;
    
//Инициализируем данные для подписи
SignedData = Новый COMОбъект("CAPICOM.SignedData");
    
Строка64=Base64Строка(Новый ДвоичныеДанные(ИмяВременногоФайла));
Строка64=Прав(Строка64,СтрДлина(Строка64)-4);
SignedData.Content = Строка64;
    
//SignedData.Content = DataToSign;
    
//Сформируем подпись
Подпись = SignedData.Sign(Signer, 1, CAPICOM_ENCODE_BASE64);
12 Gleb K
 
28.07.16
18:22
Ап
13 Gleb K
 
29.07.16
14:38
Попробовал сделать через обертку .Net
В толстом клиенте все работает.
Из модуля http-сервиса пула приложений запускаемого от этого же пользователя - падает на первой строке как-будто COM интерфейс не зарегистрирован.

БиблиотекаNET = новый COMОбъект("NetObjectToIDispatch45");
X509Certificate2 = БиблиотекаNET.СоздатьОбъект("System.Security.Cryptography.X509Certificates.X509Certificate2","C:\Cert.pfx", "123456");
RSACryptoServiceProvider = X509Certificate2.PrivateKey;
UTF8Encoding = БиблиотекаNET.СоздатьОбъект("System.Text.UTF8Encoding");
МассивБайтСообщения = UTF8Encoding.GetBytes(ТелоОтветаXML);
CryptoConfig = БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.CryptoConfig");
МассивБайтПодписиСообщения = RSACryptoServiceProvider.SignData(МассивБайтСообщения, CryptoConfig.MapNameToOID("SHA1"));
Convert = БиблиотекаNET.ПолучитьТип("System.Convert");
ПодписьBase64Строка = Convert.ToBase64String(МассивБайтПодписиСообщения);


Интересно это фундаментальные ограничения или какой-то косяк с правами доступа?
14 Serginio1
 
29.07.16
14:43
Возможно не зарегистрирован. Там нужно в поставке идет RegAsm.bat
который нужно запустить от администратора

Внутри
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe  "%~dp0NetObjetToIDispatch45.dll" /codebase

%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe  "%~dp0NetObjetToIDispatch45.dll" /codebase
15 Serginio1
 
29.07.16
14:44
Ну и  посмотреть настройки пула какой .Net FrameWork использует
16 Gleb K
 
29.07.16
14:46
(15) Зарегистрирован батником, в толстом клиенте на этой же машине код полностью отрабатывает. А при запуске через пул приложений IIS на вызов http-сервиса - падает.
17 Gleb K
 
29.07.16
14:48
(15) В настройках пула 1С рекомендует ставить Без управляемого кода, но я пробовал ставить 4 Net все-равно падает.
18 Serginio1
 
29.07.16
14:49
Там 2 строчки одна для 32 разрядного (Толстый клиент)
Вторая для 64 разрядного.
Запусти из под cmd
19 Gleb K
 
29.07.16
14:50
(18) Запускал cmd под админскими правами и оттуда уже батник.
В реестре вроде прописался HKEY_CLASSES_ROOT\CLSID\{8693BBEC-C964-4478-AFCB-E8D15FD8F4F6}
20 Serginio1
 
29.07.16
14:51
Попробуй для проверки из фонового задания запустить
21 Gleb K
 
29.07.16
14:51
Пул приложений 32 разрядный.
22 Serginio1
 
29.07.16
14:52
Может прав на папку не хватает?
23 Gleb K
 
29.07.16
14:54
(22) Папку с dll ? Права полные для текущего пользователя - в толстом клиенте все отрабатывает, через пул приложений под правами того же текущего пользователя - нет.
24 Serginio1
 
29.07.16
14:55
Кстати ProgID DFDADA57-B22C-4276-928A-8B91C9891FF1
Посмотри права DCOM
25 Gleb K
 
29.07.16
14:55
(20) Спасибо, позже попробую.
26 Serginio1
 
29.07.16
14:57
27 Gleb K
 
29.07.16
14:57
(24) Это через оснастку Службы компонентов\Настройка Dcom ?
28 Gleb K
 
29.07.16
14:59
(26) У меня база стартует в файловом режиме.
29 Gleb K
 
29.07.16
15:00
(26) Политики попробую попозже.
30 Serginio1
 
29.07.16
15:01
31 Gleb K
 
29.07.16
15:08
(14) При регистрации он кстати ругался на ключ /codebase но потом написал, что типы успешно зарегистрированы
32 Gleb K
 
29.07.16
15:12
(30) У меня в дереве Dcom нет NetObjetToIDispatch45
Дерево смотрю 32 разрядное через mmc comexp.msc /32
33 Serginio1
 
29.07.16
15:41
(31) Кстати а в роли от кого запускается 1С стоит галка Automation
34 Serginio1
 
29.07.16
15:47
Попробуй установить Привилегированный режим
35 Gleb K
 
29.07.16
15:49
Сейчас поставил общие права на объекты Dom и прописал права в локальных политиках, теперь ошибка Отказано в доступе. Но сервер еще не перезагружал.
36 Gleb K
 
29.07.16
15:55
(33) Стоит
(34) Не помогло

Сейчас опять выдает ошибку Класс не зарегистрирован.
37 Gleb K
 
29.07.16
15:57
(24) Такой объект тоже зарегистрирован HKEY_CLASSES_ROOT\CLSID\{DFDADA57-B22C-4276-928A-8B91C9891FF1}
38 Serginio1
 
29.07.16
16:03
(25) Такое впечатление, что нет у тебя доступа к реестру.
39 Serginio1
 
29.07.16
16:13
40 Gleb K
 
29.07.16
16:13
(38) Хочешь прикол?

JS=Новый COMОбъект("MSScriptControl.ScriptControl");
JS.Language="jscript";
JS.Timeout=-1;

попытка
    
СтрКода="function SignFile(FileName,Cert,OutFileName)
    |{
    |   NET=new ActiveXObject(""NetObjectToIDispatch45"");
    | return(NET);
    |}
    |";

JS.AddCode(СтрКода);
БиблиотекаNET=JS.Run("SignFile");

//До сюда код выполняется и в БиблиотекаNET сидит COMОбъект
а на следующей строке все падает с ошибкой "Ошибка при вызове метода контекста (СоздатьОбъект): Произошла исключительная ситуация (mscorlib): Адресат вызова создал исключение."

X509Certificate2 = БиблиотекаNET.СоздатьОбъект("System.Security.Cryptography.X509Certificates.X509Certificate2","C:\Users\g.kondratyev\Desktop\leader\GKazimut360.pfx", "azimut360");
41 Serginio1
 
29.07.16
16:15
Посмотри настройки пула
http://professorweb.ru/my/ASP_NET/sites/level3/3_3.php
42 Serginio1
 
29.07.16
16:18
Попробуй просто ПолучитьТип

X509Certificate2 =БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.X509Certificates.X509Certificate2");

X509Certificate2 = БиблиотекаNET.СоздатьОбъектX509Certificate2,"C:\Users\g.kondratyev\Desktop\leader\GKazimut360.pfx", "azimut360");

А сервис запускаешь от g.kondratyev
43 Gleb K
 
29.07.16
16:21
(41) Там все вроде ок.
(42) Пул идентити сейчас g.kondratyev
44 Gleb K
 
29.07.16
16:25
(42) С ПолучитьТип() полет нормальный
45 Serginio1
 
29.07.16
16:28
Значит проблема доступа к ,"C:\Users\g.kondratyev\Desktop\leader\GKazimut360.pfx",

Попробуй просто найти файл

Можно создать и так
X509Certificate2 =БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.X509Certificates.X509Certificate2");

Сертификат = БиблиотекаNET.СоздатьОбъект(X509Certificate2,"C:\Users\g.kondratyev\Desktop\leader\GKazimut360.pfx", "azimut360");
46 Gleb K
 
29.07.16
16:30
(45) На второй строке этот код вызывает исключение.
47 Gleb K
 
29.07.16
16:32
(45) Права на файл у g.kondratyev полные
48 Serginio1
 
29.07.16
16:34
Понятно. Проверь просто
файл=Новый Файл(путь);
Файл.Существует();
49 Gleb K
 
29.07.16
16:38
(48) Да, вы правы Файл.Существует() = Ложь
в чем может быть причина?
50 Serginio1
 
29.07.16
16:44
Mожет  С русская?
51 Gleb K
 
29.07.16
16:52
(50) Путь копипастил с проводника и в толстом клиенте он работает :(
52 Gleb K
 
29.07.16
17:03
Переместил файл поближе и перевел в нижний регистр: c:\1cbase\gk.pfx

Теперь файл существует, но при попытке
X509Certificate2 = БиблиотекаNET.СоздатьОбъект(X509Certificate2, ФайлКлюча, Пароль);

падает:
"Ошибка при вызове метода контекста (СоздатьОбъект): Произошла исключительная ситуация (NetObjetToIDispatch45): Ссылка на объект не указывает на экземпляр объекта."
53 Gleb K
 
29.07.16
17:03
(52) аа, походу понял косяк
54 Gleb K
 
29.07.16
17:06
Исправил, но код
JS=Новый COMОбъект("MSScriptControl.ScriptControl");
JS.Language="jscript";
JS.Timeout=-1;
    
СтрКода="function SignFile(FileName,Cert,OutFileName)
    |{
    |   NET=new ActiveXObject(""NetObjectToIDispatch45"");
    | return(NET);
    |}
    |";

JS.AddCode(СтрКода);
БиблиотекаNET=JS.Run("SignFile");

X509Cert2 = БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.X509Certificates.X509Certificate2");
X509Certificate2 = БиблиотекаNET.СоздатьОбъект(X509Cert2, ФайлКлюча, Пароль);

все-равно падает на последней строке  "Ошибка при вызове метода контекста (СоздатьОбъект): Произошла исключительная ситуация (mscorlib): Адресат вызова создал исключение.""
55 Serginio1
 
29.07.16
17:11
Ты кстати
врап=новый COMОбъект("NetObjectToIDispatch45");
    врап.ВыводитьСообщениеОбОшибке=ложь;


И можно
Попытка
X509Certificate2 = БиблиотекаNET.СоздатьОбъект(X509Cert2, ФайлКлюча, Пароль);        
    исключение
        
    Сообщить(Врап.ВСтроку(Врап.ПоследняяОшибка));
    конецПопытки
56 Serginio1
 
29.07.16
17:12
А что, за ошибка?
57 Gleb K
 
29.07.16
17:20
(56)
ОшибкаNET = БиблиотекаNET.ВСтроку(БиблиотекаNET.ПоследняяОшибка);

содержит строку "неопределено"
58 Serginio1
 
29.07.16
17:25
А
Сообщить(ОписаниеОшибки());
59 Gleb K
 
29.07.16
17:25
(58) Ошибка при вызове метода контекста (СоздатьОбъект): Произошла исключительная ситуация (mscorlib): Адресат вызова создал исключение.
60 Serginio1
 
29.07.16
17:29
61 Serginio1
 
29.07.16
17:34
62 Gleb K
 
29.07.16
17:37
(61) Serginio1 огромное спасибо за помощь, попробую импорт завтра, а также через X509Store.
63 Serginio1
 
29.07.16
17:40
Для флагов есть OR
Например




Код на C#
new X509Certificate2(fileName, keyPassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable)

Код на 1С
Сертификат=X509Certificate2(fileName, keyPassword,Врап.OR( X509KeyStorageFlags.MachineKeySet, X509KeyStorageFlags.PersistKeySet, X509KeyStorageFlags.Exportable));
64 Serginio1
 
29.07.16
17:42
Вернее
Сертификат=Врап.СоздатьОбъект(X509Cert2,fileName, keyPassword,Врап.OR( X509KeyStorageFlags.MachineKeySet, X509KeyStorageFlags.PersistKeySet, X509KeyStorageFlags.Exportable));
65 Gleb K
 
30.07.16
17:37
(30) Перезагрузил сервер, настройки прав не решили ситуацию.
66 Gleb K
 
30.07.16
17:40
Пробую сейчас через хранилище


//Инициализируем перечисления
StoreLocation = БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.X509Certificates.StoreLocation"); //LocalMachine, CurrentUser
OpenFlags = БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.X509Certificates.OpenFlags");
X509FindType = БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.X509Certificates.X509FindType");

//Инициализируем класс хранилища
X509Store = БиблиотекаNET.СоздатьОбъект("System.Security.Cryptography.X509Certificates.X509Store", "My", StoreLocation.LocalMachine);

//Открываем хранилище
X509Store.Open(OpenFlags.ReadWrite);//ReadOnly

//Находим сертификат
Certificates = X509Store.Certificates.Find(X509FindType.FindByThumbprint, "A624B6AE158E677113D2FCE3E66E332A342E0A87", Истина);
Enumerator = Certificates.GetEnumerator();
Enumerator.MoveNext();
X509Certificate2 = Enumerator.Current;

RSACryptoServiceProvider = X509Certificate2.PrivateKey;

//На последней строке код падает

Ошибка при получении значения атрибута контекста (PrivateKey): Неизвестная ошибка

System.Reflection.TargetInvocationException: Адресат вызова создал исключение. ---> System.Security.Cryptography.CryptographicException: Не удается найти указанный файл.
67 Serginio1
 
30.07.16
23:12
Попробуй 63
68 Serginio1
 
30.07.16
23:13
69 Gleb K
 
01.08.16
00:16
(68) Хорошая статья, но странно это, т.к. у меня в пуле приложений стоит Загрузить профиль пользователя = True, т.е. с этой настройкой должно работать создание объекта сертификата из файла, но нет.
Далее предлагается поместить сертификат в хранилище компа, дать права на него пользователю под которым запускается пул, и достать его из хранилища, что собственно я успешно и делаю, но при обращении к закрытому ключу объекта сертификат получаю грабли.
70 Gleb K
 
01.08.16
00:29
(63) Эврика! Рабочим оказался следующий код:

JS=Новый COMОбъект("MSScriptControl.ScriptControl");
JS.Language="jscript";
JS.Timeout=-1;
    
СтрКода="function GetNet()
    |{
    |   NET=new ActiveXObject(""NetObjectToIDispatch45"");
    | return(NET);
    |}
    |";

JS.AddCode(СтрКода);
БиблиотекаNET=JS.Run("GetNet");

X509Certificate2 = БиблиотекаNET.СоздатьОбъект("System.Security.Cryptography.X509Certificates.X509Certificate2");
X509KeyStorageFlags = БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.X509Certificates.X509KeyStorageFlags");

X509Certificate2.import(ПолноеИмяФайлаКлюча, Пароль, БиблиотекаNET.OR(X509KeyStorageFlags.MachineKeySet, X509KeyStorageFlags.PersistKeySet, X509KeyStorageFlags.Exportable));

RSACryptoServiceProvider = X509Certificate2.PrivateKey;
UTF8Encoding = БиблиотекаNET.СоздатьОбъект("System.Text.UTF8Encoding");
МассивБайтСообщения = UTF8Encoding.GetBytes(ТелоОтветаXML);
CryptoConfig = БиблиотекаNET.ПолучитьТип("System.Security.Cryptography.CryptoConfig");
МассивБайтПодписиСообщения = RSACryptoServiceProvider.SignData(МассивБайтСообщения, CryptoConfig.MapNameToOID("SHA1"));
Convert = БиблиотекаNET.ПолучитьТип("System.Convert");
ПодписьBase64Строка = Convert.ToBase64String(МассивБайтПодписиСообщения);

Serginio1 огромное спасибо за участие, хотя еще мне нужно сделать проверку подписи входящего запроса, но если будут проблемы напишу сюда и надеюсь не откажите еще раз помочь.
71 Serginio1
 
01.08.16
09:35
Основная теорема систематики: Новые системы плодят новые проблемы.