Проблемы с проверкой файла pkcs7

У меня большая и странная проблема с файлами ценных бумаг PKCS7. Я создаю файл p7s, как это предлагается в http://www.thatsjava.com/java-tech/85019/, где он создает файл и проверяет его, используя только библиотеки Sun. Работает нормально.
Проблема начинается, когда я хочу проверить этот файл. Он возвращает это исключение:

java.security.SignatureException: Signature encoding error
        at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:185)
        at java.security.Signature$Delegate.engineVerify(Signature.java:1140)
        at java.security.Signature.verify(Signature.java:592)
        at sun.security.pkcs.SignerInfo.verify(SignerInfo.java:374)
        at sun.security.pkcs.PKCS7.verify(PKCS7.java:494)
        at sun.security.pkcs.PKCS7.verify(PKCS7.java:511)
        at sun.security.pkcs.PKCS7.verify(PKCS7.java:533)
        at firma.FirmaDigitalImpl.firmarCadenaSun(FirmaDigitalImpl.java:553)
        at firma.FirmaDigitalImpl.firmarCadena(FirmaDigitalImpl.java:249)
        at firma.FirmaDigitalImpl.firmarCadena(FirmaDigitalImpl.java:147)
        at firma.TestFirma.main(TestFirma.java:75)
Caused by: java.io.IOException: Sequence tag error
        at sun.security.util.DerInputStream.getSequence(DerInputStream.java:280)
        at sun.security.rsa.RSASignature.decodeSignature(RSASignature.java:209)
        at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:174)
        ... 10 more

Но проблемы возникают не всегда, а только с типом сертификатов, используемых для подписи. Я объясню лучше. У меня есть два сертификата (хранящихся на смарт-карте), и первый работает нормально; Я создаю p7s, а затем правильно проверяю, но второй сертификат позволяет мне создать файл p7s, но когда я его проверяю, он возвращает SignatureException. Я думал, что файл p7s неправильный, но я проверил его с другими приложениями, и он выглядит правильно. Кроме того, этот файл отправляется кидает веб-сервис, и он возвращает, что все в порядке!

И для получения дополнительной информации, если файл p7s создан с помощью разных инструментов (.net и capicom) и одного и того же сертификата, я могу правильно проверить.

Я искал решение, но ничего. Я нашел такое же исключение в подобных ситуациях, но либо предложенное решение не работает для меня, либо оно не появляется.

Любые советы по поиску решения будут очень признательны.


person Marcos    schedule 02.03.2011    source источник


Ответы (2)


Это может быть проблема с кодировкой: текст или двоичный файл. PKCS7 может быть либо в двоичном формате с кодировкой DER, либо в формате PEM (то есть в формате DER с кодировкой base64). Откройте файлы в текстовом редакторе (например, блокноте) и посмотрите, какой из них работает: двоичный или текстовый.

person zvrba    schedule 02.03.2011
comment
Пробую в обоих форматах, результат тот же. Если проблема была в этом, не меняется в зависимости от используемого сертификата. Спасибо за ваше мнение - person Marcos; 03.03.2011

Спустя более двух недель я заметил, в чем была проблема, хотя и не нашел полного решения.

Сначала я извлек проблему из файла PKCS7 и воспроизвел исключение со следующим исходным кодом:

import diz.firma.keyStore.SmartCard;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;

public class TestFirma3 {
public static void main(String args[]) throws Exception {
    //Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    SmartCard sm = new SmartCard();
    KeyStore ks = sm.loadKeyStore("1234");
    //KeyPair keyPair = generateKeyPair(999);


    byte[] data = "original".getBytes("UTF-8");
    //byte[] data = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 };
    //byte[] digitalSignature = signData(data, keyPair.getPrivate());
    byte[] digitalSignature = signData(data,
            (PrivateKey)ks.getKey(sm.getAlias(), null),ks.getProvider());

    boolean verified;

    //verified = verifySig(data, keyPair.getPublic(), digitalSignature);
    verified = verifySig(data, ks.getCertificate(sm.getAlias()).
            getPublicKey(),ks.getProvider(), digitalSignature);
    System.out.println("verified:" + verified) ;

    //keyPair = generateKeyPair(888);
    //verified = verifySig(data, keyPair.getPublic(), digitalSignature);
    //System.out.println(verified);

  }

  public static byte[] signData(byte[] data, PrivateKey key,Provider p) throws Exception {
    Signature signer = Signature.getInstance("SHA1withRSA",p);
    //Signature signer = Signature.getInstance("SHA1withRSA",Security.getProviders()[10]);

    signer.initSign(key);
    signer.update(data);
    return (signer.sign());
  }

  public static boolean verifySig(byte[] data, PublicKey key, Provider p, byte[] sig) throws Exception {
    Signature signer = Signature.getInstance("SHA1withRSA",p);
    //Signature signer = Signature.getInstance("SHA1withRSA");
    signer.initVerify(key);
    signer.update(data);

    boolean valido = false;
    try{
        valido = signer.verify(sig);
    }catch(Exception e){
        e.printStackTrace();
        valido = false;
    }
    return valido;

  }

  public static KeyPair generateKeyPair(long seed) throws Exception {
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("DSA");
    SecureRandom rng = SecureRandom.getInstance("SHA1PRNG", "SUN");
    rng.setSeed(seed);
    keyGenerator.initialize(1024, rng);

    return (keyGenerator.generateKeyPair());
  }
}

В этом коде (взято из примера в нете) я сменил ключ генератора и взял его со своей карты. Я снова получил исключение, не используя файлы PKCS7.

Глядя на всех провайдеров (с помощью Security.getProviders() вы можете получить их всех; они определены в файле java.security, но его можно добавить или взять из него во время выполнения), и я использовал всех для подписи и проверки, я узнал что:

  1. Если при создании экземпляра подписи не выбран ни один поставщик, по умолчанию используется SunRsaSign.
  2. Моя подпись проверяется двумя провайдерами:
    а) провайдером SunMSCAPI, который использует Microsoft Crypt API.
    б) провайдером, созданным устройством чтения смарт-карт, в моем случае Siemens.
  3. При считывании другой смарт-карты, не принадлежащей Siemens, она проверяется с помощью SunRsaSign и SunJSSE.

На данный момент я выясняю проблему и обходной путь, используя SunMSCAPI для проверки, но мне нужно выполнить проверку на машине IBM. Программное обеспечение Siemens предоставляет возможность установки в Unix, но я не могу заставить его работать. И использование SunMSCAPI, я полагаю, недоступно для IBM.

Итак, мне нужно найти поставщика, который правильно проверяет в IMB подпись, которую SunRsaSign возвращает SignatureException.

person Marcos    schedule 18.03.2011