Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M Новый топик    Ответить
 Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
Здравствуйте! Уже неделю бьюсь с этой задачей. Использовал https://habrahabr.ru/company/intersystems/blog/137145/, но хранилище типа "FloppyStore" на linux не подходит. Пробовал пересобрать библиотеку iscjcp.jar для "HDImagesStore" - вроде стало получаться (Хранилище видит), но вылетает
........... java.security.ProviderException
at ru.CryptoPro.JCP.KeyStore.u.g(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.u.b(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.engineGetKey(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.JCPKeyStore.engineGetKey(Unknown Source)
То ли КриптоПро неправильно настроена, то ли в коде ошибка.
Кто-нибудь реализовывал на Cache?
27 апр 16, 09:31    [19111226]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
П.С.М.
Member

Откуда: Из СССР
Сообщений: 453
KaIIIuct
Кто-нибудь реализовывал на Cache?

Да
KaIIIuct
хранилище типа "FloppyStore" на linux не подходит. Пробовал пересобрать библиотеку iscjcp.jar для "HDImagesStore" - вроде стало получаться (Хранилище видит)

Тоже пересобирал iscjcp.jar (чтобы понимало не только FloppyStore). У нас всё работало. Ближе к вечеру, как будет свободное время, посмотрю подробнее чего и как. А может и раньше кто ответит.
27 апр 16, 10:12    [19111379]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,
Заранее спасибо
27 апр 16, 10:27    [19111469]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
П.С.М.
Member

Откуда: Из СССР
Сообщений: 453
KaIIIuct,
По-моему менялись только два класса:
+ JcpFacade
package isc.jcp;

import java.util.*;

import java.io.IOException;

import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.xml.xpath.XPathFactory;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.ws.security.WSSecurityException;

import java.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.cert.X509Certificate;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.KeyStoreException;
import java.security.UnrecoverableKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import com.objsys.asn1j.runtime.Asn1Exception;
//import javax.swing.JFrame;
//import javax.swing.JOptionPane;

/**
 * Фасад для работы с JCP из веб-сервисов Cache.
 */
public class JcpFacade
{
  private static final String ENVELOPE_NS_URI = "http://schemas.xmlsoap.org/soap/envelope/";
  private static final String WSSE_NS_URI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
  private static final String DS_NS_URI = "http://www.w3.org/2000/09/xmldsig#";
  
  private static XPathFactory xpathFactory = XPathFactory.newInstance();

  /**
   * Формирует ЭЦП в формате XML Signature (ds:Signature).
   *
   * @param xmlFragmentBytes XML-документ, элемент которого подписывается; передается в виде массива байт в кодировке UTF-8
   * @param wsuId значение атрибута wsu:Id подписываемаего элемента
   * @param certFilename имя файла сертификата в формате X.509, соответствующего секретному ключу
   * @param keyPassword пароль для доступа к секретному ключу
   * @return Строка, содержащая XML-элемент ds:Signature.
   * @throws XMLSecurityException
   * @throws IOException
   * @throws CertificateException
   * @throws KeyStoreException
   * @throws NoSuchAlgorithmException
   * @throws UnrecoverableKeyException
   */
   public static String createSignature(byte[] xmlFragmentBytes, String wsuId, String certFilename, String keyPassword, String StoreName)
    throws XMLSecurityException, IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException
  {
    String xmlFragment = new String(xmlFragmentBytes, "UTF-8");
    
    
    JcpUtils.initJcp();
    if (StoreName == null)
    {
      throw new RuntimeException("Не задано имя хранилища");
    }
    //String storename = JcpUtils.getStoreName("c:\\store.cfg"); 
 
    //JcpUtils.ShowMessage(storename);
    
    KeyStore keyStore = JcpUtils.getFloppyStore(StoreName,keyPassword);
    if (keyStore == null)
    {
      throw new RuntimeException("Не удалось получить доступ к хранилищу ключей " + StoreName);
    }
    
    //Test(keyStore);
    
    //JcpUtils.ShowMessage("Получение сертификата");  
    X509Certificate certificate = JcpUtils.getCertificate(certFilename);
    if (certificate == null)
    {
    //    JcpUtils.ShowMessage("Не смогли получить");  
        throw new RuntimeException("Не найден сертификат");
    }
    //JcpUtils.ShowMessage("Получение закрытого ключа");  
    PrivateKey privateKey = getPrivateKey(keyStore, certificate, keyPassword, certFilename);
    if (privateKey == null)
    {
      throw new RuntimeException("Не найден закрытый ключ");
    }
    //JcpUtils.ShowMessage("Работа с xml");  
    Document document = XmlUtils.deserialize(xmlFragment);
    
    IdAttrResourceResolver resolver;
    synchronized(xpathFactory)
    {
      resolver = new IdAttrResourceResolver(xpathFactory);
    }
    
    Element signature = JcpUtils.signDocuments(
        document,
        new String[] {"#" + wsuId},
        resolver,
        certificate,
        privateKey);
   
    return XmlUtils.serializeNode(signature);
  }
   
  /**
   * Проверяет валидность ЭЦП для SOAP-сообщения.
   *
   * @param soapEnvelopeBytes подписанное SOAP-сообщение; передается в виде массива байт в кодировке UTF-8
   * @return Boolean
   * @throws XMLSecurityException
   * @throws IOException
   * @throws WSSecurityException
   * @throws CertificateException
   */
  public static Boolean verifySignature(byte[] soapEnvelopeBytes)
    throws XMLSecurityException, IOException, WSSecurityException, CertificateException
  {
    String soapEnvelope = new String(soapEnvelopeBytes, "UTF-8");
    
    //FileOutputStream f = new FileOutputStream("C://Temp//verifySignature.xml");
    //f.write(soapEnvelopeBytes);
    //f.flush();
  
    Document envelopeDocument = XmlUtils.deserialize(soapEnvelope);

    Element header = findSoapHeader(envelopeDocument);
    if (header == null)
      throw new RuntimeException("Не найден элемент SOAP Header");
    
    NodeList securityNL = header.getElementsByTagNameNS(WSSE_NS_URI, "Security");
    if (securityNL == null || securityNL.getLength() == 0)
    {
      throw new RuntimeException("Не найден элемент WS-Security");
    }
    
    IdAttrResourceResolver resolver;
    synchronized(xpathFactory)
    {
      resolver = new IdAttrResourceResolver(xpathFactory);
    }
    
    JcpUtils.initJcp();
    
    int signaturesVerified = 0;
    for (int i = 0; i < securityNL.getLength(); i++)
    {
      Element signature = getSignatureElement((Element)securityNL.item(i));
      if (signature == null) continue;
      
      if (!JcpUtils.verifySignature(signature, resolver))
      {
        signaturesVerified = -1;
        break;
      }
      
      signaturesVerified++;
    }
    
    if (signaturesVerified == 0)
    {
      throw new RuntimeException("Не найден элемент WS-Security, содержащий элемент Signature");
    }
    
    return Boolean.valueOf(signaturesVerified > -1);
  }
  
  private static Element findSoapHeader(Document envelopeDocument)
  {
    Element header = null;
    Element envelope = envelopeDocument.getDocumentElement();
    
    if (!"Envelope".equals(envelope.getLocalName()) || !ENVELOPE_NS_URI.equals(envelope.getNamespaceURI()))
      throw new RuntimeException("Не найден элемент SOAP Envelope");
    
    Element body = XmlUtils.getFirstChildElement(envelope);
    if (body == null || !ENVELOPE_NS_URI.equals(body.getNamespaceURI()))
      throw new RuntimeException("Не найдены элементы SOAP Header / SOAP Body");
    
    if ("Header".equals(body.getLocalName()))
    {
      header = body;
      body = XmlUtils.getNextChildElement(envelope, header);
      if (body == null || !ENVELOPE_NS_URI.equals(body.getNamespaceURI()))
        throw new RuntimeException("Не найден элемент SOAP Body");
    }

    if (!"Body".equals(body.getLocalName()))
      throw new RuntimeException("Не найден элемент SOAP Body");
    
    return header;
  }
  
  private static Element getSignatureElement(Element security)
  {
    NodeList sigNL = security.getElementsByTagNameNS(DS_NS_URI, "Signature");
    if (sigNL == null || sigNL.getLength() == 0)
    {
      return null;
    }
    else if (sigNL.getLength() > 1)
    {
      throw new RuntimeException("Найдено несколько элементов Signature в рамках одного элемента Security");
    }
    else
    {
      return (Element)sigNL.item(0);
    }
  }
  
  private static PrivateKey getPrivateKey(KeyStore keyStore, X509Certificate certificate, String password, String certFilename)
    throws KeyStoreException, CertificateEncodingException, NoSuchAlgorithmException, UnrecoverableKeyException
  {
    PrivateKey result = null;
    
    Enumeration aliases = keyStore.aliases();
    String alias = JcpUtils.getAlias(certFilename);
    if (alias == null) {
        while (aliases.hasMoreElements())
        {
          alias = (String)aliases.nextElement();

          if (keyStore.isKeyEntry(alias))
          {
            Key key = getKey(keyStore, alias, password);
            if (key instanceof PrivateKey)
            {
              result = (PrivateKey)key;
              X509Certificate floppyCertificate = (X509Certificate)keyStore.getCertificate(alias);

              if (floppyCertificate != null)
              {
                if (Arrays.equals(certificate.getEncoded(), floppyCertificate.getEncoded()))
                  return result;
                else
                  result = null;
              }
            }
          }
        }
    }
    else 
    {
      if (keyStore.isKeyEntry(alias))
      {
        Key key = getKey(keyStore, alias, password);
        if (key instanceof PrivateKey)
        {
          result = (PrivateKey)key;
          X509Certificate floppyCertificate = (X509Certificate)keyStore.getCertificate(alias);

          if (floppyCertificate != null)
          {
            if (Arrays.equals(certificate.getEncoded(), floppyCertificate.getEncoded()))
              return result;
            else
              result = null;
          }
        }
      }
    }
    
    if ((keyStore.size() == 1) && (result != null))
      return result;
    else   
      return null;
  }
  
private static Key getKey(KeyStore keyStore, String Alias, String Password) 
        throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException
{
    Key key;
    
    if (Password != null)
    {
      key = keyStore.getKey(Alias, Password.toCharArray());
    }
    else
    {
      key = keyStore.getKey(Alias, null);
    }
    return key;
}
/**
   * Формирует ЭЦП для произвольного массива байт.
   *
   * @param data подписываемый массив байт
   * @param certFilename имя файла сертификата в формате X.509, соответствующего секретному ключу
   * @param keyPassword пароль для доступа к секретному ключу
   * @return ЭЦП
   * @throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, SignatureException, Asn1Exception, CertificateEncodingException, InvalidKeyException
   */
  public static byte[] createCMSSignature(byte[] data, String certFilename, String keyPassword, String StoreName)
    throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, SignatureException, Asn1Exception, CertificateEncodingException, InvalidKeyException
  {
    JcpUtils.initJcp();
    
    if (StoreName == null)
    {
      throw new RuntimeException("Не задано имя хранилища");
    }
    //String StoreName = JcpUtils.getStoreName("c:\\store.cfg"); 
    KeyStore keyStore = JcpUtils.getFloppyStore(StoreName, keyPassword);
    if (keyStore == null) throw new RuntimeException("Не удалось получить доступ к хранилищу ключей "+StoreName);
    
    X509Certificate certificate = JcpUtils.getCertificate(certFilename);
    if (certificate == null) throw new RuntimeException("Не найден сертификат");
    
    PrivateKey privateKey = getPrivateKey(keyStore, certificate, keyPassword, certFilename);
    if (privateKey == null) throw new RuntimeException("Не найден закрытый ключ");
    
    return JcpUtils.createCMS(data, new PrivateKey[] { privateKey }, new Certificate[] { certificate }, true);
  }
  
  /**
   * Проверка CMS подписи массива байт.
   *
   * @param cmsBytes CMS подпись
   * @param data подписанные данные; null = поверяются подписанные данные, содержащиеся внутри CMS; если имеются вложенные в CMS подписанные данные, то data игнорируется
   * @param certFilename имя файла сертификата в формате X.509; null = использовать сертификат, содержащийся в CMS; если имеются вложенные в CMS сертификаты, то certFilename игнорируется
   * @return верна ли подпись
   * @throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException, CertificateException, KeyStoreException
   */
  public static Boolean verifyCMSSignature(byte[] cmsBytes, byte[] data, String certFilename)
    throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException, CertificateException, KeyStoreException
  {
    X509Certificate certificate = null;
    if (certFilename != null)
    {
      certificate = JcpUtils.getCertificate(certFilename);
      if (certificate == null) {
            throw new RuntimeException("Не найден сертификат");
        }
    }
    
    JcpUtils.initJcp();
    
    return Boolean.valueOf(JcpUtils.verifyCMS(cmsBytes, certificate == null ? null : new Certificate[] { certificate }, data));
  }  
  /**

   */
  public static byte[] getDigest(byte[] data) 
          throws IOException, NoSuchAlgorithmException
  {  
    JcpUtils.initJcp(); 
    return JcpUtils.getDigest(data);
  }
}

и
+ JcpUtils
package isc.jcp;

import java.util.*;
import java.io.*;

import org.w3c.dom.Element;
import org.w3c.dom.Document;

import java.security.DigestInputStream;
import java.security.Security;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.MessageDigest;
import java.security.Signature;
import java.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;

import org.apache.xml.security.Init;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.transforms.Transforms;

import org.apache.ws.security.message.token.SecurityTokenReference;
import org.apache.ws.security.WSDocInfo;
import org.apache.ws.security.message.token.X509Security;
import org.apache.ws.security.WSSecurityException;

import ru.CryptoPro.JCP.JCP;
import ru.CryptoPro.JCP.params.OID;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.CMSVersion;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.CertificateChoices;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.CertificateSet;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.ContentInfo;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.DigestAlgorithmIdentifier;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.DigestAlgorithmIdentifiers;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.EncapsulatedContentInfo;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.IssuerAndSerialNumber;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignatureAlgorithmIdentifier;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignatureValue;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignedData;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignerIdentifier;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignerInfo;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignerInfos;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Attribute;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.CertificateSerialNumber;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Name;
import ru.CryptoPro.JCP.tools.Array;

import com.objsys.asn1j.runtime.Asn1Type;
import com.objsys.asn1j.runtime.Asn1BerDecodeBuffer;
import com.objsys.asn1j.runtime.Asn1BerEncodeBuffer;
import com.objsys.asn1j.runtime.Asn1Null;
import com.objsys.asn1j.runtime.Asn1ObjectIdentifier;
import com.objsys.asn1j.runtime.Asn1OctetString;
import com.objsys.asn1j.runtime.Asn1Exception;
import java.security.UnrecoverableKeyException;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
 * Контейнер для полезных методов работы с КриптоПро JCP.
 */
public class JcpUtils
{
  /** Алгоритм подписи (ГОСТ Р 34.10-2001) **/
  public static final String signMethod = "http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411";

  /** Алгоритм хеширования, используемый при подписи (ГОСТ Р 34.11-94) **/
  public static final String digestMethod = "http://www.w3.org/2001/04/xmldsig-more#gostr3411"; 

  private static final String STR_CMS_OID_SIGNED = "1.2.840.113549.1.7.2";
  private static final String DIGEST_OID = JCP.GOST_DIGEST_OID;
  private static final String STR_CMS_OID_DATA = "1.2.840.113549.1.7.1";
  private static final String SIGN_OID = JCP.GOST_EL_KEY_OID;
  private static final String STR_CMS_OID_CONT_TYP_ATTR = "1.2.840.113549.1.9.3";
  private static final String STR_CMS_OID_DIGEST_ATTR = "1.2.840.113549.1.9.4";
  private static final String DIGEST_ALG_NAME = JCP.GOST_DIGEST_NAME;
  
  /** Хранилище ключей типа FloppyStore **/
  private static KeyStore floppyStore;
  
  /** Кэш сертификатов **/
  private static Map certificates = new HashMap();
  
  /** Фабрика сертификатов **/
  private static CertificateFactory certificateFactory;

  /**
   * Инициализирует JCP и XML Security.
   */
  public synchronized static void initJcp()
  {
    ru.CryptoPro.JCP.JCP jcp = new ru.CryptoPro.JCP.JCP();
    if (Security.getProvider(jcp.getName()) == null)
    {
      Security.addProvider(jcp);
    }
    
    if (!ru.CryptoPro.JCPxml.xmldsig.JCPXMLDSigInit.isInitialized())
    {
      ru.CryptoPro.JCPxml.xmldsig.JCPXMLDSigInit.init();
    }
    
    if (!Init.isInitialized())
    {
      Init.init();
    }
  }
  /*
   * Вернет имя хранилищиа
   */
  public static String getStoreName(String file)
    throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException
  {
      String str = "";
      try {
        BufferedReader in = new BufferedReader(new FileReader(file));
        while ((str = in.readLine()) != null) {            
            //JOptionPane.showMessageDialog(frame, str);
            if (!"".equals(str)) {
                break;
            }
        }
        in.close();
    } catch (IOException e) {}
    if ("".equals(str)) {
            str = "FloppyStore";
    } 
    //JOptionPane.showMessageDialog(frame, str);
    return str;
  }
  /**
   * Возвращает ссылку на хранилище ключей FloppyStore.
   *
   * @return KeyStore
   * @throws IOException
   * @throws CertificateException
   * @throws KeyStoreException
   * @throws NoSuchAlgorithmException
   */
  public static KeyStore getFloppyStore(String StoreName, String keyPassword )
    throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException
  {
    if (floppyStore == null)
      initFloppyStore(StoreName, keyPassword);
    
    return floppyStore;
  }

  /**
   * Инициализирует хранилище ключей FloppyStore.
   *
   * @throws IOException
   * @throws CertificateException
   * @throws KeyStoreException
   * @throws NoSuchAlgorithmException
   */
  private synchronized static void initFloppyStore(String StoreName, String keyPassword )
    throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException
  {
    floppyStore = KeyStore.getInstance(StoreName);
    if (floppyStore != null)
    {
        if (keyPassword == null) {
            floppyStore.load(null, null);
        }
        else {
            floppyStore.load(null, keyPassword.toCharArray());            
        }
        
    }
    
   /*   
      */
  }
  
  /**
   * Загружает сертификат в формате X.509 из потока.
   *
   * @param is поток, содержащий сертификат в формате X.509
   * @return X509Certificate
   * @throws CertificateException
   */
  public synchronized static X509Certificate getCertificate(InputStream is)
    throws CertificateException
  {
    if (certificateFactory == null)
      certificateFactory = CertificateFactory.getInstance("X.509");
      
    X509Certificate cert = null;
    try
    {
      cert = (X509Certificate)certificateFactory.generateCertificate(new BufferedInputStream(is));
    }
    finally
    {
      try
      {
        is.close();
      }
      catch (IOException ignore)
      {}
    }
    return cert;
  }

  /**
   * Загружает сертификат в формате X.509 из файла. Использует кэш сертификатов.
   *
   * @param file имя файла, содержащего сертификат в формате X.509
   * @return X509Certificate
   * @throws FileNotFoundException
   * @throws CertificateException
   */
  public synchronized static X509Certificate getCertificate(String file)
    throws CertificateException, KeyStoreException, UnsupportedEncodingException
  {
      X509Certificate cert = null;
      if (file != null) {
          String alias = getAlias(file);
          if (alias == null) { 
            try {
              FileInputStream ifStream = new FileInputStream(file);
              if (certificates.containsKey(file)) {
                    return (X509Certificate)certificates.get(file);
                }
              cert = getCertificate(ifStream);
            }
            catch(FileNotFoundException ignore)
            { }
            if (cert != null) {
                certificates.put(file, cert);
                return cert;
            }
          }
          else {
              cert = (X509Certificate) floppyStore.getCertificate(alias); 
          }
      }
    return cert;
  }

  // Получить алиас
public static String getAlias(String fileoralias) 
        throws KeyStoreException
{
    if (fileoralias == null) return null;
    Enumeration aliasesEnum = floppyStore.aliases();
    String result = null;
    while (aliasesEnum.hasMoreElements()) {        
          String alias = aliasesEnum.nextElement().toString();                          
          if (alias.indexOf(fileoralias)!= -1) {
              result = alias;
              break;
        }
    }
    return result;
}
 // Просто функция ShowMessage
 public static void ShowMessage(String Message)
 {
    JFrame frame=new JFrame();
    JOptionPane.showMessageDialog(frame, Message);  
 }
  /**
   * Проверяет валидность ЭЦП.
   *
   * @param signatureElement XML-элемент ds:Signature
   * @param resourceResolver реализация <code>org.apache.xml.security.utils.resolver.ResourceResolverSpi</code>, используемая при проверке подписи
   * @return boolean
   * @throws XMLSecurityException
   * @throws WSSecurityException
   * @throws CertificateException
   */
  public static boolean verifySignature(Element signatureElement, ResourceResolverSpi resourceResolver)
    throws XMLSecurityException, WSSecurityException, CertificateException
  {
    XMLSignature signature = new XMLSignature(signatureElement, "");
    if (signature.getSignedInfo().getLength() == 0)
      throw new RuntimeException("No signed resources");
    
    signature.addResourceResolver(resourceResolver);

    KeyInfo ki = signature.getKeyInfo();
    if (ki == null) 
      throw new RuntimeException("KeyInfo element not found");
    else if (ki.isEmpty()) 
      throw new RuntimeException("Empty KeyInfo element");
    else if (ki.containsX509Data())
      return signature.checkSignatureValue(ki.getX509Certificate());
    else if (ki.getPublicKey() != null)
      return signature.checkSignatureValue(ki.getPublicKey());
    
    // далее - сложный случай
    Element kiChild = XmlUtils.getFirstChildElement(ki.getElement());
    if (kiChild == null) throw new RuntimeException("Empty KeyInfo element");
    
    SecurityTokenReference tref = new SecurityTokenReference(kiChild);
    if (!tref.containsReference() || (tref.getReference() == null))
      throw new RuntimeException("SecurityTokenReference does not contain a direct reference (i.e. <wsse:Reference> element)");
    else if (!X509Security.X509_V3_TYPE.equals(tref.getReference().getValueType()))
      throw new RuntimeException("Reference value type \"" + tref.getReference().getValueType() + "\" is not supported");
      
    Element tokenEl = tref.getTokenElement(signatureElement.getOwnerDocument(), new WSDocInfo(signatureElement.getOwnerDocument()), null);
    X509Security token = new X509Security(tokenEl);
    X509Certificate cert = getCertificate(new ByteArrayInputStream(token.getToken()));
    
    return signature.checkSignatureValue(cert);
  }
  
  /**
   * Формирует ЭЦП в формате XML Signature (ds:Signature).
   *
   * @param targetDoc XML-документ (DOM), элементы которого подписываются
   * @param uris массив ссылок (URI) на подписываемые элементы
   * @param resourceResolver реализация <code>org.apache.xml.security.utils.resolver.ResourceResolverSpi</code>, используемая при формировании подписи
   * @param certificate сертификат в формате X.509, соответствующий секретному ключу, используемому при формировании подписи
   * @param privateKey секретный ключ, используемый при формировании подписи
   * @return XML-элемент ds:Signature
   * @throws XMLSecurityException
   */
  public static Element signDocuments(Document targetDoc, String[] uris, ResourceResolverSpi resourceResolver, X509Certificate certificate, PrivateKey privateKey)
    throws XMLSecurityException
  {
    XMLSignature sig = new XMLSignature(targetDoc, "", signMethod, Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);

    Transforms transforms = new Transforms(targetDoc);
    transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
    
    for (int i = 0; i < uris.length; i++)
      sig.addDocument(uris[i], transforms, digestMethod);

    sig.getSignedInfo().addResourceResolver(resourceResolver);

    sig.addKeyInfo(certificate);
    sig.sign(privateKey);
    
    return sig.getElement();
  }
  
  /**
   * Формирует ЭЦП для произвольного массива байт.
   *
   * @param data подписываемый массив байт
   * @param keys массив секретных ключей, используемый при формировании подписи
   * @param certs массив сертификатов в формате X.509, соответствующий массиву секретных ключей
   * @param detached признак необходимости создания detached ЭЦП - см. http://notary.cryptopro.ru/Notary_Help.htm
   * @return ЭЦП
   * @throws IOException, SignatureException, Asn1Exception, CertificateEncodingException, NoSuchAlgorithmException, InvalidKeyException
   */
   public static byte[] createCMS(byte[] data, PrivateKey[] keys, Certificate[] certs, boolean detached)
    throws IOException, SignatureException, Asn1Exception, CertificateEncodingException, NoSuchAlgorithmException, InvalidKeyException
  {
    //create CMS
    final SignedData cms = new SignedData();
    cms.version = new CMSVersion(1);

    final ContentInfo all = new ContentInfo();
    all.contentType = new Asn1ObjectIdentifier(new OID(STR_CMS_OID_SIGNED).value);
    all.content = cms;
    
    // digest
    final DigestAlgorithmIdentifier a = new DigestAlgorithmIdentifier(new OID(DIGEST_OID).value);
    a.parameters = new Asn1Null();
    cms.digestAlgorithms = new DigestAlgorithmIdentifiers(1);
    cms.digestAlgorithms.elements[0] = a;
    
    if (detached)
      cms.encapContentInfo = new EncapsulatedContentInfo(new Asn1ObjectIdentifier(new OID(STR_CMS_OID_DATA).value), null);
    else
      cms.encapContentInfo = new EncapsulatedContentInfo(new Asn1ObjectIdentifier(new OID(STR_CMS_OID_DATA).value), new Asn1OctetString(data));

    // certificates
    final int ncerts = certs.length;
    cms.certificates = new CertificateSet(ncerts);
    cms.certificates.elements = new CertificateChoices[ncerts];
    for (int i = 0; i < cms.certificates.elements.length; i++)
    {
      final ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate certificate = new ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate();
      final Asn1BerDecodeBuffer decodeBuffer = new Asn1BerDecodeBuffer(certs[i].getEncoded());
      certificate.decode(decodeBuffer);
      cms.certificates.elements[i] = new CertificateChoices();
      cms.certificates.elements[i].set_certificate(certificate);
    }
    
    // Signature.getInstance
    final Signature signature = Signature.getInstance(JCP.GOST_EL_SIGN_NAME);
    byte[] sign;
    
    // signer infos
    final int nsign = keys.length;
    cms.signerInfos = new SignerInfos(nsign);
    for (int i = 0; i < cms.signerInfos.elements.length; i++)
    {
      signature.initSign(keys[i]);
      signature.update(data);
      sign = signature.sign();

      final CertificateSerialNumber num = new CertificateSerialNumber(((X509Certificate)certs[i]).getSerialNumber());
      final byte[] encodedName = ((X509Certificate)certs[i]).getIssuerX500Principal().getEncoded();
      final Asn1BerDecodeBuffer nameBuf = new Asn1BerDecodeBuffer(encodedName);
      final Name name = new Name();
      name.decode(nameBuf);

      cms.signerInfos.elements[i] = new SignerInfo();
      cms.signerInfos.elements[i].version = new CMSVersion(1);
      cms.signerInfos.elements[i].sid = new SignerIdentifier();
      cms.signerInfos.elements[i].sid.set_issuerAndSerialNumber(new IssuerAndSerialNumber(name, num));
      cms.signerInfos.elements[i].digestAlgorithm = new DigestAlgorithmIdentifier(new OID(DIGEST_OID).value);
      cms.signerInfos.elements[i].digestAlgorithm.parameters = new Asn1Null();
      cms.signerInfos.elements[i].signatureAlgorithm = new SignatureAlgorithmIdentifier(new OID(SIGN_OID).value);
      cms.signerInfos.elements[i].signatureAlgorithm.parameters = new Asn1Null();
      cms.signerInfos.elements[i].signature = new SignatureValue(sign);
    }
    
    // encode
    final Asn1BerEncodeBuffer asnBuf = new Asn1BerEncodeBuffer();
    all.encode(asnBuf, true);
    
    return asnBuf.getMsgCopy();
  }
  
  /**
   * Проверка CMS подписи массива байт.
   *
   * @param cmsBytes CMS подпись
   * @param certs массив сертификатов в формате X.509; null = использовать сертификат, содержащийся в CMS; если имеются вложенные в CMS сертификаты, то certs игнорируется
   * @param data подписанные данные; null = поверяются подписанные данные, содержащиеся внутри CMS; если имеются вложенные в CMS подписанные данные, то data игнорируется
   * @return верна ли подпись
   * @throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException, CertificateException
   */
  public static boolean verifyCMS(byte[] cmsBytes, Certificate[] certs, byte[] data)
    throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException, CertificateException
  {
    int validsign = 0;
    
    final Asn1BerDecodeBuffer asnBuf = new Asn1BerDecodeBuffer(cmsBytes);
    final ContentInfo all = new ContentInfo();
    all.decode(asnBuf);
    if (!new OID(STR_CMS_OID_SIGNED).eq(all.contentType.value)) throw new RuntimeException("Формат подписи не поддерживается");
    
    final SignedData cms = (SignedData)all.content;
    
    final byte[] text;
    if (cms.encapContentInfo.eContent != null)
      text = cms.encapContentInfo.eContent.value;
    else if (data != null)
      text = data;
    else
      throw new RuntimeException("Нет данных для проверки подписи");
      
    OID digestOid = null;
    final DigestAlgorithmIdentifier digestAlgorithmIdentifier = new DigestAlgorithmIdentifier(new OID(DIGEST_OID).value);
    for (int i = 0; i < cms.digestAlgorithms.elements.length; i++)
    {
      if (cms.digestAlgorithms.elements[i].algorithm.equals(digestAlgorithmIdentifier.algorithm))
      {
        digestOid = new OID(cms.digestAlgorithms.elements[i].algorithm.value);
        break;
      }
    }
    if (digestOid == null) throw new RuntimeException("Неизвестный дайджест");
    
    final OID eContTypeOID = new OID(cms.encapContentInfo.eContentType.value);
    if (cms.certificates != null)
    {
      //Проверка на вложенных сертификатах
      for (int i = 0; i < cms.certificates.elements.length; i++)
      {
        final Asn1BerEncodeBuffer encBuf = new Asn1BerEncodeBuffer();
        cms.certificates.elements[i].encode(encBuf);

        final CertificateFactory cf = CertificateFactory.getInstance("X.509");
        final X509Certificate cert = (X509Certificate)cf.generateCertificate(encBuf.getInputStream());

        for (int j = 0; j < cms.signerInfos.elements.length; j++)
        {
          final SignerInfo info = cms.signerInfos.elements[j];
          if (!digestOid.equals(new OID(info.digestAlgorithm.algorithm.value))) throw new RuntimeException("Подпись не соответствует сертификату");
          final boolean checkResult = verifyOnCert(cert, cms.signerInfos.elements[j], text, eContTypeOID);
          if (checkResult) validsign += 1;
        }
      }
    }
    else if (certs != null)
    {
      //Проверка на указанных сертификатах
      for (int i = 0; i < certs.length; i++)
      {
        final X509Certificate cert = (X509Certificate)certs[i];
        for (int j = 0; j < cms.signerInfos.elements.length; j++)
        {
          final SignerInfo info = cms.signerInfos.elements[j];
          if (!digestOid.equals(new OID(info.digestAlgorithm.algorithm.value))) throw new RuntimeException("Подпись не соответствует сертификату");
          final boolean checkResult = verifyOnCert(cert, cms.signerInfos.elements[j], text, eContTypeOID);
          if (checkResult) validsign += 1;
        }
      }
    }
    else
    {
       // Certificates for validation not found
    }
    
    return (cms.signerInfos.elements.length == validsign);
  }
  
  /**
   * Попытка проверки подписи на указанном сертификате
   *
   * @param cert сертификат для проверки
   * @param text текст для проверки
   * @param info подпись
   * @param eContentTypeOID
   * @return верна ли подпись
   * @throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException
   */
  private static boolean verifyOnCert(X509Certificate cert, SignerInfo info, byte[] text, OID eContentTypeOID)
    throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException
  {
    //подпись
    final byte[] sign = info.signature.value;
    
    //данные для проверки подписи
    final byte[] data;
    if (info.signedAttrs == null)
    {
      //аттрибуты подписи отсутствуют
      data = text;
    }
    else
    {
      //присутствуют аттрибуты подписи (SignedAttr)
      final Attribute[] signAttrElem = info.signedAttrs.elements;

      //проверка аттрибута content-type
      final Asn1ObjectIdentifier contentTypeOid = new Asn1ObjectIdentifier((new OID(STR_CMS_OID_CONT_TYP_ATTR)).value);
      Attribute contentTypeAttr = null;
      for (int r = 0; r < signAttrElem.length; r++)
      {
        final Asn1ObjectIdentifier oid = signAttrElem[r].type;
        if (oid.equals(contentTypeOid)) contentTypeAttr = signAttrElem[r];
      }

      if (contentTypeAttr == null)
        throw new RuntimeException("Отсутствует атрибут, отвечающий за структуру подписи");

      if (!contentTypeAttr.values.elements[0].equals(new Asn1ObjectIdentifier(eContentTypeOID.value)))
        throw new RuntimeException("Недопустимая структура подписи");

      //проверка аттрибута message-digest
      final Asn1ObjectIdentifier messageDigestOid = new Asn1ObjectIdentifier((new OID(STR_CMS_OID_DIGEST_ATTR)).value);
      Attribute messageDigestAttr = null;
      for (int r = 0; r < signAttrElem.length; r++)
      {
        final Asn1ObjectIdentifier oid = signAttrElem[r].type;
        if (oid.equals(messageDigestOid)) messageDigestAttr = signAttrElem[r];
      }
      if (messageDigestAttr == null)
        throw new RuntimeException("Не найдено значение дайджеста");

      //вычисление messageDigest
      final ByteArrayInputStream stream = new ByteArrayInputStream(text);
      final MessageDigest digest = MessageDigest.getInstance(DIGEST_ALG_NAME);
      final DigestInputStream digestStream = new DigestInputStream(stream, digest);
      while (digestStream.available() != 0)
        digestStream.read();
        
      final Asn1Type open = messageDigestAttr.values.elements[0];
      final Asn1OctetString hash = (Asn1OctetString)open;
      if (!Array.toHexString(digest.digest()).equals(Array.toHexString(hash.value)))
        throw new RuntimeException("Недопустимое значение дайджеста");

      //данные для проверки подписи
      final Asn1BerEncodeBuffer encBufSignedAttr = new Asn1BerEncodeBuffer();
      info.signedAttrs.encode(encBufSignedAttr);
      data = encBufSignedAttr.getMsgCopy();
    }

    // проверка подписи
    final Signature signature = Signature.getInstance(JCP.GOST_EL_SIGN_NAME);
    signature.initVerify(cert);
    signature.update(data);
    
    return signature.verify(sign);
  }
  
public static byte[] getBytesFromFile(File file) throws IOException {
    InputStream is = new FileInputStream(file);
    long length = file.length();
    if (length > Integer.MAX_VALUE) {
        return null;
    }
 
    byte[] bytes = new byte[(int)length];
 
    // Read in the bytes
    int offset = 0;
    int numRead = 0;
    while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
        offset += numRead;
    }
 
    // Ensure all the bytes have been read in
    if (offset < bytes.length) {
        throw new IOException("Could not completely read file "+file.getName());
    }
 
    // Close the input stream and return bytes
    is.close();
    return bytes;
}

    /**
     * Метод печатает список алиасов
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     * @throws UnrecoverableKeyException
     */
    public static void prnListAlias(String StoreName, String keyPassword) 
           throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException, IOException, CertificateException
  {
      initJcp();
      getFloppyStore(StoreName,keyPassword);
      try {
      Enumeration aliases = floppyStore.aliases();
        while (aliases.hasMoreElements())
        {
          String alias = (String)aliases.nextElement();
          System.out.print("alias: " + alias);
          System.out.println("");
        }
      } 
      catch (Exception ex) {} 
      floppyStore = null;
  }
    /**
     * Метод возвращает значение хеш для строки text
     * @param text принимает входную строку, для которой необходимо вычислить хеш
     * @return возвращает хеш
     */
    public static byte[] getDigest(byte[] text) 
            throws IOException, NoSuchAlgorithmException
    {
        //вычисление messageDigest
      final ByteArrayInputStream stream = new ByteArrayInputStream(text);
      final MessageDigest digest;
        digest = MessageDigest.getInstance(DIGEST_ALG_NAME);
      final DigestInputStream digestStream;
        digestStream = new DigestInputStream(stream, digest);
      while (digestStream.available() != 0) {
            digestStream.read();
        }
        
      //final Asn1Type open = messageDigestAttr.values.elements[0];
      //final Asn1OctetString hash = (Asn1OctetString)open;
      //if (!Array.toHexString(digest.digest()).equals(Array.toHexString(hash.value)))
       // throw new RuntimeException("Недопустимое значение дайджеста");
      return digest.digest();
      //return Array.toHexString(digest.digest());
    }
}


Соответственно потом проекции классов незабыть перегенерить.
Основное изменение:
String createSignature(byte[] xmlFragmentBytes, String wsuId, String certFilename, String keyPassword, String StoreName)
Может принимать имя хранилища (StoreName, не только FloppyStore) и путь к файлу сертификата или имя алиаса (certFilename).
Как то так...
27 апр 16, 23:47    [19115133]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Спасибо большое,будем пробовать
28 апр 16, 07:41    [19115499]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
	... java.security.ProviderException
	at ru.CryptoPro.JCP.KeyStore.u.g(Unknown Source)
	at ru.CryptoPro.JCP.KeyStore.u.b(Unknown Source)
	at ru.CryptoPro.JCP.KeyStore.ContainerStore.engineGetKey(Unknown Source)
	at ru.CryptoPro.JCP.KeyStore.JCPKeyStore.engineGetKey(Unknown Source)
	at java.security.KeyStore.getKey(KeyStore.java:804)
	at isc.jcp.JcpFacade.getKey(JcpFacade.java:287)


Тоже самое вываливается. Все делали также как описано на хабре?
Ощущение что криптопро неправильно настроена.
Не может получить ключ - сертификат,хранилище,алиас все видит.
28 апр 16, 09:46    [19115810]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
П.С.М.
Member

Откуда: Из СССР
Сообщений: 453
KaIIIuct,
Я бы с этой ошибкой пошел спрашивать туда Форум КриптоПро. Больше шансов получить полезный ответ :)
28 апр 16, 11:13    [19116313]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Да и там тоже тему завел. Спасибо
28 апр 16, 13:25    [19117243]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Напишите пожалуйста какую версию Java и КриптоПро использовали
28 апр 16, 15:21    [19117995]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
П.С.М.
Member

Откуда: Из СССР
Сообщений: 453
KaIIIuct,

Да по-моему, как в статье была jdk1.6.0_20, такую и использовали. А JCP, то ли 1.0.52, то ли 1.0.53.
12 май 16, 13:09    [19163328]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Ошибка при подписании выходит:
ОШИБКА #5023: Ошибка Java-шлюза: java.lang.NullPointerException
	at isc.jcp.XmlUtils.serializeNode(XmlUtils.java:51)
	at isc.jcp.XmlUtils.serializeNode(XmlUtils.java:38)
	at isc.jcp.JcpFacade.createSignature(JcpFacade.java:111)


Верификация успешно отрабатывает.Ключи,хранилище,сертификат - все видит
12 май 16, 14:56    [19164070]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
этот метод возвращает null
JcpUtils.signDocuments
...
    Transforms transforms = new Transforms(targetDoc);
    transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
...


Используется xmlsec-1.4.3 может и в этом дело - сейчас попробую xmlsec-1.4.6
12 май 16, 15:04    [19164137]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
Нет, дело не в xmlsec
12 май 16, 15:10    [19164207]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
Дело в этом:
XmlUtils.deserialize(xmlFragment);
Возвращает null (пустой документ). Борюсь

Помогите ребята пожалуйста, неужели никто со СМЭВ не работал?
12 май 16, 16:50    [19165037]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
+ KaIIIuct,
  public static Document deserialize(String paramString)
  {
    return deserialize(new StringReader(paramString));
  }
  
  public static Document deserialize(Reader paramReader)
  {
    DocumentBuilder localDocumentBuilder;
    try
    {
      synchronized (documentBuilderFactory)
      {
        localDocumentBuilder = documentBuilderFactory.newDocumentBuilder();
      }
    }
    catch (ParserConfigurationException localParserConfigurationException)
    {
      throw new RuntimeException(localParserConfigurationException);
    }
    return deserialize(localDocumentBuilder, paramReader);
  }
  
  public static Document deserialize(DocumentBuilder paramDocumentBuilder, Reader paramReader)
  {
    Document localDocument = null;
    try
    {
      localDocument = paramDocumentBuilder.parse(new InputSource(paramReader));
    }
    catch (SAXException localSAXException)
    {
      throw new RuntimeException(localSAXException);
    }
    catch (IOException localIOException)
    {
      throw new RuntimeException(localIOException);
    }
    return localDocument;
  }
12 май 16, 16:56    [19165084]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
П.С.М.
Member

Откуда: Из СССР
Сообщений: 453
В общем, потратил немного времени и настроил всё с нуля.

- Нашел у себя виртуалку с убунту на которой стояла Cache:
cat /proc/version
Linux version 3.13.0-32-generic (buildd@roseapple) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #57-Ubuntu SMP Tue Jul 15 03:51:12 UTC 2014
w $zv
Cache for UNIX (SUSE Linux Enterprise Server for x86-32) 2014.1.2 (Build 753U) Tue Jul 22 2014 10:58:32 EDT
- Сходил на Oracle Java Archive и скачал jre1.6.0_20 (jre-6u20-linux-i586.bin в моём случае).
Яву поставил в /opt/java/jre1.6.0_20

- Взял имевшийся у меня дистрибутив CryptoPRO JCP (jcp.1.0.52).
Криптопро распаковал в /opt/JCP

- запустил инсталлятор криптопро:
sh ./install.sh /opt/java/jre1.6.0_20 00000-00000-00000-00000-00000
(соответственно вместо нулей реальный ключ).

- скопировал в папку /opt/java/jre1.6.0_2/lib/ext дополнительные файлы:
commons-logging-1.1.1.jar, wss4j-1.6.3.jar, xmlsec-1.4.6.jar ну и модернизированный iscjcp.jar

- Добавил новую запись в таблицу %Net_Remote.ObjectGateway в области %SYS:
insert into %Net_Remote.ObjectGateway(NameTypeServerPortJavaHome
values ('JCPGate''1''127.0.0.1''55555''/opt/java/jre1.6.0_20')
- Запускаем шлюз:
>##class(%Net.Remote.Service).StartGateway("JCPGate")
1
- и сгенерим проекцию для ява класса:
>##class(%Net.Remote.Java.JavaGateway).%ExpressImport("isc.jcp.JcpFacade""55555")
- Далее, в классе smev.JcpUtils прописываем параметры, у меня так (есть доп. параметры PASSWORD и STORENAME):
/// Контейнер для методов, используемых при работе с КриптоПро JCP
Class smev.JcpUtils
{

/// Порт, на котором запущен Java-gateway
Parameter 
JAVAGATEWAYPORT = 55555;

/// Адрес сервера, на котором запущен Java-gateway
Parameter 
JAVAGATEWAYSERVER = "127.0.0.1";

/// Имя файла сертификата или название контейнера (можно посмотреть в панеле управления CryptoPro JCP)
Parameter 
CERTFILENAME = "название_контейнера";

/// Пароль к хранилищу
Parameter 
PASSWORD = "пароль";

/// OCFStore - eToken
/// RutokenStore - ruToken
/// FloppyStore - floppy drive disc
Parameter 
STORENAME = "FloppyStore";

...
- Затем, функция createSignature в классе smev.JcpUtils, она немного модернизирована (добавлено использование STORENAME и PASSWORD):
/// Вызов Java-метода создания ЭЦП.
/// Предполагается, что в рамках XML-документа (аргумент xml) имеется элемент с атрибутом wsu:Id="<значение аргумента wsuId>". Именно для этого элемента будет создана подпись.
/// certFilename - имя файла сертификата. Если не указано, то берется значение параметра CERTFILENAME.
/// keyStorePassword - пароль хранилища секретных ключей, по умолчанию пустой.
ClassMethod 
createSignature(xml As %Stream.ObjectwsuId As %StringOutput signature As %StringcertFilename As %String ""keyStorePassword As %String ""StoreName As %String ""As %Status
{
  
#dim sc As %Status $$$OK
  
  if 
(certFilename ""set certFilename = ..#CERTFILENAME
  if 
(keyStorePassword ""set keyStorePassword = ..#PASSWORD
  if 
(StoreName ""set StoreName = ..#STORENAME
  
  #dim 
jgw As %Net.Remote.Gateway ##class(%Net.Remote.Gateway).%New()
  
  
// третий аргумент - для совместимости со старыми версиями 
  
set sc jgw.%Connect(..#JAVAGATEWAYSERVER, ..#JAVAGATEWAYPORT$ZU(5))
  
if $$$ISERR(scquit sc
  
  
try
  
{
    
set signature ##class(isc.jcp.JcpFacade).createSignature(jgwxmlwsuIdcertFilenamekeyStorePasswordStoreName)
  
}
  
catch
  
{
    
set sc %objlasterror
  
}
  
  
do jgw.%Disconnect()
  
  
quit sc
}
- Для проверки работы подписи возьмём кусок кода из метода InitializeForService класса smev.JcpSignature и запустим в терминале:
>dummyBody=##class(%GlobalBinaryStream).%New()

>SOAPWSUns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"

>do dummyBody.Write("<dummy wsu:Id=""tst_id"" xmlns:wsu="""_SOAPWSUns_"""/>")

>##class(smev.JcpUtils).createSignature(dummyBody"tst_id", .dummySignature)
1
+ zw dummySignature
>zw dummySignature
dummySignature="<ds:Signature xmlns:ds=""http://www.w3.org/2000/09/xmldsig#"">"_$c(10)_"<ds:SignedInfo>"_$c(10)_"<ds:CanonicalizationMethod Algorithm=""http://www.w3.org/2001/10/xml-exc-c14n#""/>"_$c(10)_"<ds:SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411""/>"_$c(10)_"<ds:Reference URI=""#tst_id"">"_$c(10)_"<ds:Transforms>"_$c(10)_"<ds:Transform Algorithm=""http://www.w3.org/2001/10/xml-exc-c14n#""/>"_$c(10)_"</ds:Transforms>"_$c(10)_"<ds:DigestMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#gostr3411""/>"_$c(10)_"<ds:DigestValue>jBjUqmWW5HxPJCXw/c2t4yiREwO7b6fQAkE51nVnraA=</ds:DigestValue>"_$c(10)_"</ds:Reference>"_$c(10)_"</ds:SignedInfo>"_$c(10)_"<ds:SignatureValue>"_$c(10)_"ZyGjMlWPfdYVLGUJYb7qCRgkCAELl0fYSvLAWzBHL4DeIMZuITzKkTwFoUXhUeLW/Ra73Cm4Pymp"_$c(10)_"TXBytVGdiw=="_$c(10)_"</ds:SignatureValue>"_$c(10)_"<ds:KeyInfo>"_$c(10)_"<ds:X509Data>"_$c(10)_"</ds:X509Data>"_$c(10)_"</ds:KeyInfo>"_$c(10)_"</ds:Signature>"_$c(10)
Как видим, всё работает.
13 май 16, 02:12    [19167164]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Спасибо за инструкцию, буду пробовать с нуля.
13 май 16, 08:21    [19167282]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
П.С.М.
Member

Откуда: Из СССР
Сообщений: 453
KaIIIuct
Дело в этом:
XmlUtils.deserialize(xmlFragment);
Возвращает null (пустой документ)
Да, и будьте внимательны с кодировкой. Как правило, русский текст в файле и неправильная работа с кодировкой приводя к таким вот нулпоинтэксепшен.
13 май 16, 08:50    [19167340]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Пробовал тоже выполнить ваш код в терминале - та же ошибка. Устанавливаю с "0" на виртуалку.
13 май 16, 09:42    [19167494]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Попробовал на виртуалке правда под windows - jre6+jcp1.0.54
все остальное тоже самое - ничего лишнего

Таже ошибка при

	S dummyBody=##class(%GlobalBinaryStream).%New()
 
	S SOAPWSUns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"

	do dummyBody.Write("<dummy wsu:Id=""tst_id"" xmlns:wsu="""_SOAPWSUns_"""/>")

	w ##class(smev.JcpUtils).createSignature(dummyBody, "tst_id", .dummySignature)


ОШИБКА #5023: Ошибка Java-шлюза: java.lang.NullPointerException
	at isc.jcp.XmlUtils.serializeNode(XmlUtils.java:51)
	at isc.jcp.XmlUtils.serializeNode(XmlUtils.java:38)
	at isc.jcp.JcpFacade.createSignature(JcpFacade.java:110)


Не меняли класс XMLUtils?
13 май 16, 13:38    [19168817]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
П.С.М.
Member

Откуда: Из СССР
Сообщений: 453
KaIIIuct
Не меняли класс XMLUtils?

Вроде нет, но точно сказать пока не могу. Вечером еще раз посмотрю.

А если вы возьмёте первоначальный iscjcp.jar? С ним тоже ошибка???


ЗЫ.
Также, не помешает отладочный вывод в iscjcp.jar сделать )))
И после каждой изменения в iscjcp.jar не забывать перезапускать шлюз
w ##class(%Net.Remote.Service).StopGateway("JCPGate")
w ##class(%Net.Remote.Service).StartGateway("JCPGate")
13 май 16, 14:04    [19168962]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Огромное человеческое СПАСИБО Вам за помощь - удалось мне победить на виртуалке, думаю и на остальном тоже удастся!
Дело было в классе XmlUtils - слава google :)

Было так
public class XmlUtils
{
  private static TransformerFactory transformerFactory ;
  private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  
  static


На просторах интернета заметил, что перед перед определением
localTransformer = transformerFactory.newTransformer();

Вызывается
... = TransformerFactory.newInstance();


И в нашем классе XmlUtils я тоже решил поменять определение свойства на:
private static TransformerFactory transformerFactory = TransformerFactory.newInstance();
13 май 16, 14:30    [19169057]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
KaIIIuct
Member

Откуда: Россия, Поволжье
Сообщений: 41
П.С.М.,

Еще раз спасибо!!!
13 май 16, 14:31    [19169063]     Ответить | Цитировать Сообщить модератору
 Re: Подписать SOAP-сообщение для СМЭВ  [new]
П.С.М.
Member

Откуда: Из СССР
Сообщений: 453
KaIIIuct
П.С.М.,

Еще раз спасибо!!!

Пожалуйста, чем смог, т.с. :)

Посмотрел XmlUtils и у меня и в исходниках в статье он одинаков. Вот он:

+ XmlUtils
package isc.jcp;

import java.util.*;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Контейнер для полезных методов работы с XML.
 */
public class XmlUtils
{
  private static TransformerFactory transformerFactory = TransformerFactory.newInstance();
  private static DocumentBuilderFactory documentBuilderFactory;
  static
  {
    documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setNamespaceAware(true);
  }
  
  /**
   * Сериализует XML DOM в строку.
   *
   * @param node вершина DOM
   * @return Cтрока с XML
   */
  public static String serializeNode(Node node)
  {
    return serializeNode(node, true, true);
  }
  
  /**
   * Сериализует XML DOM в строку.
   *
   * @param node вершина DOM
   * @param omitXmlDeclaration признак того, что в результат не нужно включить XML declaration (по умолчанию true)
   * @return Cтрока с XML
   */
  public static String serializeNode(Node node, boolean omitXmlDeclaration)
  {
    return serializeNode(node, omitXmlDeclaration, true);
  }

  /**
   * Сериализует XML DOM в строку.
   *
   * @param node вершина DOM
   * @param omitXmlDeclaration признак того, что в результат не нужно включить XML declaration (по умолчанию true)
   * @param indent признак необходимости добавлять отступы (по умолчанию true)
   * @return Cтрока с XML
   */  
  public static String serializeNode(Node node, boolean omitXmlDeclaration, boolean indent)
  {
    Transformer serializer;
    try
    {
      serializer = transformerFactory.newTransformer();
    }
    catch (TransformerConfigurationException e)
    {
      throw new RuntimeException(e);
    }

    serializer.setOutputProperty(OutputKeys.METHOD, "xml");
    serializer.setOutputProperty(OutputKeys.INDENT, (indent ? "yes" : "no"));
    serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, (omitXmlDeclaration ? "yes" : "no"));

    StringWriter writer = new StringWriter();
    try
    {
      serializer.transform(new DOMSource(node), new StreamResult(writer));
    }
    catch (TransformerException e)
    {
      throw new RuntimeException(e);
    }

    return writer.toString();
  }
  
  /**
   * Десериализует XML из строки в DOM.
   *
   * @param s строка, содержащая XML
   * @return XML-документ (DOM)
   */
  public static Document deserialize(String s)
  {
    return deserialize(new StringReader(s));
  }
  
  /**
   * Десериализует XML из <code>java.io.Reader</code> в DOM.
   *
   * @param reader экземпляр <code>java.io.Reader</code>, содержащий XML
   * @return XML-документ (DOM)
   */
  public static Document deserialize(Reader reader)
  {
    DocumentBuilder documentBuilder;
    try
    {
      synchronized (documentBuilderFactory)
      {
        documentBuilder = documentBuilderFactory.newDocumentBuilder();
      }
    }
    catch (ParserConfigurationException e)
    {
      throw new RuntimeException(e);
    }
    
    return deserialize(documentBuilder, reader);
  }

  /**
   * Десериализует XML из <code>java.io.Reader</code> в DOM, используя указанный <code>javax.xml.parsers.DocumentBuilder</code>.
   *
   * @param documentBuilder объект-реализация <code>javax.xml.parsers.DocumentBuilder</code>, который будет использован при десериализации XML
   * @param reader экземпляр <code>java.io.Reader</code>, содержащий XML
   * @return XML-документ (DOM)
   */
  public static Document deserialize(DocumentBuilder documentBuilder, Reader reader)
  {
    Document doc = null;  
    try
    {
      doc = documentBuilder.parse(new InputSource(reader));
    }
    catch (SAXException e)
    {
      throw new RuntimeException(e);
    }
    catch (IOException ioe)
    {
      throw new RuntimeException(ioe);
    }
    
    return doc;
  }

  /**
   * Вычисляет XPath-выражение.
   *
   * @param xpath подготовленный объект <code>javax.xml.xpath.XPath</code>
   * @param doc XML-документ (DOM)
   * @param xpathExpression XPath-выражение
   * @return Результирующий массив вершин DOM
   */
  public static Node[] evalXPath(XPath xpath, Document doc, String xpathExpression)
  {
    NodeList nodelist;
    try
    {
      nodelist = (NodeList)xpath.evaluate(xpathExpression, doc, XPathConstants.NODESET);
    }
    catch (XPathExpressionException e)
    {
      throw new RuntimeException("Error evaluating XPath expression " + xpathExpression + ": " + e.getMessage(), e);
    }

    Node[] result = new Node[nodelist.getLength()];
    for (int i = 0; i < nodelist.getLength(); i++)
      result[i] = nodelist.item(i);

    return result;
  }
  
  /**
   * Возвращает первый дочерний XML-элемент.
   *
   * @param elem родительский XML-элемент
   * @return Первый дочерний XML-элемент
   */
  public static Element getFirstChildElement(Element elem)
  {
    for (Node n = elem.getFirstChild(); n != null; n = n.getNextSibling())
    {
      if (n.getNodeType() == Node.ELEMENT_NODE)
      {
        return (Element)n;
      }
    }
    return null;
  }

  /**
   * Возвращает следующий после указанного дочерний XML-элемент.
   *
   * @param parentElem родительский XML-элемент
   * @param currentElem текущий дочерний XML-элемент
   * @return Следующий после указанного дочерний XML-элемент
   */
  public static Element getNextChildElement(Element parentElem, Element currentElem)
  {
    boolean currElemFound = false;
    
    for (Node n = parentElem.getFirstChild(); n != null; n = n.getNextSibling())
    {
      if (n.getNodeType() == Node.ELEMENT_NODE)
      {
        if (currElemFound)
          return (Element)n;
        else
          currElemFound = (currentElem == (Element)n);
      }
    }
    return null;
  }
}


И да, и там и там:
public class XmlUtils
{
  private static TransformerFactory transformerFactory = TransformerFactory.newInstance();
 ...

Т.ч., похоже, что у Вас кто-то уже приложил руку к XmlUtils )))
14 май 16, 22:35    [19173892]     Ответить | Цитировать Сообщить модератору
Все форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M Ответить