Ошибка проверки PKCS7: повреждены данные ASN1 - PullRequest
0 голосов
/ 15 октября 2018

Я занимаюсь разработкой Java-класса, который подписывает текстовые файлы в формате PKCS7.Я обнаружил, что это можно сделать, используя библиотеки Sun вместо BouncyCastle, и разработал следующий метод:

    public void AssinaPKCS7(String ArquivoAssinar) {

        String SrtResultPKCS7 = "";
        byte[] Conteudo;
        byte[] Hash;
        String DadosArq = "";
        String Linha = "";
        boolean AssinValid = false;

        try {
            FileInputStream Entrada = new FileInputStream(ArquivoAssinar);
            InputStreamReader Leitor = new InputStreamReader(Entrada, Charset);
            BufferedReader Buffer = new BufferedReader(Leitor);
            Linha = Buffer.readLine();

            while (Linha != null) {
                DadosArq = DadosArq + Linha;
                Linha = Buffer.readLine();
            }

            Buffer.close();

            Conteudo = DadosArq.getBytes(Charset);

            X500Name xName = X500Name.asX500Name(Certif.getSubjectX500Principal());
            BigInteger serial = Certif.getSerialNumber();
            AlgorithmId digestAlgorithmId = new AlgorithmId(AlgorithmId.SHA_oid);
            AlgorithmId signAlgorithmId = new AlgorithmId(AlgorithmId.RSAEncryption_oid);

            MessageDigest MessDig = MessageDigest.getInstance("SHA1");
            Hash = MessDig.digest(Conteudo);

            PKCS9Attribute Atributo1 = new PKCS9Attribute(PKCS9Attribute.CONTENT_TYPE_OID, ContentInfo.DATA_OID);
            PKCS9Attribute Atributo2 = new PKCS9Attribute(PKCS9Attribute.MESSAGE_DIGEST_OID, Hash); 
            PKCS9Attributes ConjuntoAtrib = new PKCS9Attributes(new PKCS9Attribute[] {Atributo1, Atributo2}); 

            Signature Sign = Signature.getInstance(AlgoritmoAssinatura);
            Sign.initSign(PrivPass);
            Sign.update(Conteudo);
            ResultadoAssinatura = Sign.sign();

            Signature Verif = Signature.getInstance(AlgoritmoAssinatura);
            Verif.initVerify(Certif);
            Verif.update(Conteudo);
            AssinValid = Verif.verify(ResultadoAssinatura);

            if (AssinValid) {
                try {
                    SignerInfo sInfo = new SignerInfo(xName, serial, digestAlgorithmId, ConjuntoAtrib, signAlgorithmId, ResultadoAssinatura, null);

                    ContentInfo cInfo = new ContentInfo(ContentInfo.DIGESTED_DATA_OID, new DerValue(DerValue.tag_OctetString, Conteudo));

                    PKCS7 p7 = new PKCS7(new AlgorithmId[] { digestAlgorithmId }, cInfo, new java.security.cert.X509Certificate[] { Certif }, new SignerInfo[] { sInfo });

                    ByteArrayOutputStream bOut = new DerOutputStream();
                    p7.encodeSignedData(bOut);
                    byte[] encoded = bOut.toByteArray();
                    SrtResultPKCS7 = Encoder.encode(encoded);

                    FileOutputStream Saida = new FileOutputStream(ArquivoAssinar);
                    OutputStreamWriter Escritor = new OutputStreamWriter(Saida, Charset);
                    BufferedWriter BuffWriter = new BufferedWriter(Escritor); 
                    //BuffWriter.write(SrtResultPKCS7);
                    BuffWriter.write(bOut.toString());
                    BuffWriter.close();
                }
                catch (Exception E) {
                    E.printStackTrace();        
                }
            }
            else {
                System.out.println("Assinatura inválida");
            }
        }
        catch (Exception E) {
            E.printStackTrace();
        }

    }

Когда я попытался проверить полученный файл в онлайн-валидаторе https://www.receita.fazenda.gov.br/Aplicacoes/SSL/ATBHE/assinadoc/ValidadorAssinaturas.app/valida.aspx Iполучил это сообщение об ошибке:

ASN1 поврежденные данные

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

У кого-нибудь была эта проблема?И как я могу проверить результат PCKS7 в коде Java?

1 Ответ

0 голосов
/ 17 октября 2018

Я не знаю, как вы проверили подпись, кроме бессмысленной проверки в вашем коде, которая повторяет ошибку (и), но это были неверные данные, и поскольку вы не показали нам AlgoritmoAssinatura может быть,неправильный метод.У вас также есть несколько других ошибок.Вместо того, чтобы подробно их описать, вот пример, который дает действительный результат с комментариями:

// use test data for example
KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream (args[0]), args[1].toCharArray());
PrivateKey PrivKey = (PrivateKey) ks.getKey (args[2], args[1].toCharArray());
X509Certificate Certif = (X509Certificate) ks.getCertificate(args[2]);
String Message = "test";
String ArquivoAssinar = args[3];
String Charset = "ASCII"; // no idea, see below

String SrtResultPKCS7 = "";
byte[] Conteudo = Message.getBytes(Charset);
byte[] Hash;
//String DadosArq = "";
//String Linha = "";
//boolean AssinValid = false;

try {
    // the name in SignerInfo is the _Issuer_ name NOT the Subject
    X500Name xName = X500Name.asX500Name(Certif.getIssuerX500Principal());
    BigInteger serial = Certif.getSerialNumber();
    AlgorithmId digestAlgorithmId = new AlgorithmId(AlgorithmId.SHA_oid);
    AlgorithmId signAlgorithmId = new AlgorithmId(AlgorithmId.RSAEncryption_oid);

    MessageDigest MessDig = MessageDigest.getInstance("SHA1");
    Hash = MessDig.digest(Conteudo);

    PKCS9Attribute Atributo1 = new PKCS9Attribute(PKCS9Attribute.CONTENT_TYPE_OID, ContentInfo.DATA_OID);
    PKCS9Attribute Atributo2 = new PKCS9Attribute(PKCS9Attribute.MESSAGE_DIGEST_OID, Hash); 
    PKCS9Attributes ConjuntoAtrib = new PKCS9Attributes(new PKCS9Attribute[] {Atributo1, Atributo2}); 

    // when using signedattrs, signature is of the encoded attrs 
    // (without the context-implicit tag used when embedded in SignerInfo)
    Signature Sign = Signature.getInstance("SHA1withRSA");
    Sign.initSign(PrivKey);
    Sign.update(ConjuntoAtrib.getDerEncoding());
    byte[] ResultadoAssinatura = Sign.sign();

    SignerInfo sInfo = new SignerInfo(xName, serial, digestAlgorithmId, ConjuntoAtrib, signAlgorithmId, ResultadoAssinatura, null);
    // contenttype inside signed-data is data not digested-data  
    ContentInfo cInfo = new ContentInfo(ContentInfo.DATA_OID, new DerValue(DerValue.tag_OctetString, Conteudo));

    PKCS7 p7 = new PKCS7(new AlgorithmId[] { digestAlgorithmId }, cInfo, new java.security.cert.X509Certificate[] { Certif }, new SignerInfo[] { sInfo });

    ByteArrayOutputStream bOut = new DerOutputStream();
    p7.encodeSignedData(bOut);
    byte[] encoded = bOut.toByteArray();
    // Java doesn't define a class 'Encoder' so I assume this is base64
    SrtResultPKCS7 = DatatypeConverter.printBase64Binary(encoded); // gone in 11!

    FileOutputStream Saida = new FileOutputStream(ArquivoAssinar);
    OutputStreamWriter Escritor = new OutputStreamWriter(Saida, Charset);
    BufferedWriter BuffWriter = new BufferedWriter(Escritor);
    // this was correct for base64 (although the buffering is wasted)
    BuffWriter.write(SrtResultPKCS7);
    // this was nonsense -- it decodes the DER bytes as if they were characters,
    // which they aren't, and then OSW re-encodes them to probably wrong bytes
    //BuffWriter.write(bOut.toString());
    BuffWriter.close();
    // alternatively could write DER/binary with a Stream (NOT a Writer)
}
catch (Exception E) {
    E.printStackTrace();
}

Мне не ясно, какой выходной формат вы - или сайт, на который вы ссылаетесь - хотите,Использование бинарных / DER довольно распространено, но не может быть вырезано и вставлено, и с ним сложнее работать.Base64 из DER встречается редко, но не неизвестно.Если вам или им нужен стандартный формат PEM, используемый многими программами, это НЕ просто base64 из DER;это base64 разрывов строк DER PLUS через каждые 64 символа, добавлены строки dash-BEGIN и dash-END.

Кроме того, SHA-1 был прерван из-за столкновения более года;см. https://shattered.io и многочисленные вопросы о криптографии. SX и security.SX об этом.Еще до этого он был запрещен для подписи многочисленными властями с 2014 или 2015 года, включая NIST (для правительства США) и CABforum (для публичных веб-сертификатов).Я ничего не знаю о данных, которые вы подписываете, но если они каким-либо образом важны или ценны, и у вас есть возможность использовать лучший хэш в своих сигнатурах, вам следует.

ДОБАВЛЕНО: также, как я полагаю, вы понимаете, что sun.* классы не документированы, не гарантированы и могут перестать работать в любое время, когда Oracle захочет.

...