复制OpenSSL命令以使用Java对文件进行签名 [英] Replicate OpenSSL command to sign a file in Java

查看:78
本文介绍了复制OpenSSL命令以使用Java对文件进行签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要对文件签名,到目前为止,我已经使用了openssl逗号,它可以正常工作(对文件进行签名和验证).

I need to sign a file and so far I've used the openssl comman which is working fine (file is signed and verified).

openssl smime -sign -in unsigned.mobileconfig -out signed.mobileconfig -signer myCrtFile.crt -inkey myKeyFile.key -certfile bundleCertificate.crt -outform der -nodetach

但是现在我需要在运行时执行此操作,因此我需要以编程方式对文件进行签名.我正在使用BouncyCastle,但是我愿意切换到另一个库.

But now I need to do this on runtime, so I need to sign the file programmatically. I'm using BouncyCastle but I'm open to switch to another library.

我对证书不熟练,甚至对BouncyCastle也不熟练.这就是我来的.

I'm not skilled with certificates and even less with BouncyCastle. This is what I came with.

openssl命令与以下代码对应的文件是:

The corresponding files from the openssl command to the code below are:

myCrtFile.crt -> signerCertHolder
myKeyFile.key -> privateKeyInfo
bundleCertificate.crt -> certificateHolder


public byte[] sign(String message) throws IOException, CMSException, OperatorCreationException, CertificateEncodingException, MessagingException, CertificateException {
    Security.addProvider(new BouncyCastleProvider());

    PrivateKeyInfo privateKeyInfo = loadInKey();
    X509CertificateHolder signerCertHolder = loadSigner();
    X509CertificateHolder certificateCertHolder = loadCertfile();

    PrivateKey inKey = new JcaPEMKeyConverter().getPrivateKey(privateKeyInfo);

    JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
    X509Certificate signer = certificateConverter.getCertificate(signerCertHolder);
    X509Certificate certificate = certificateConverter.getCertificate(certificateCertHolder);

    List<X509Certificate> certificateList = new ArrayList();
    certificateList.add(signer);
    certificateList.add(certificate);

    Store<?> certs = new JcaCertStore(certificateList);
    ContentSigner sha1signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(inKey);
    JcaSignerInfoGeneratorBuilder jcaSignerInfoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build());

    CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();
    signGen.addSignerInfoGenerator(jcaSignerInfoGeneratorBuilder.build(sha1signer, certificate));
    signGen.addCertificates(certs);

    CMSTypedData content = new CMSProcessableByteArray(message.getBytes());
    CMSSignedData signedData = signGen.generate(content, false);
    byte[] signeddata = signedData.getEncoded();

    return signeddata;
} 

然后将byte[]保存到文件中.当我打开文件(它是MDM mobileConfig文件)时,它显示文件已签名但无法验证".我觉得我已经接近解决方案了,但是我不知道我在做什么错.

Then I save the byte[] to a file. When I open the file (it is a MDM mobileConfig file) it says "The file is signed but could not be verified". I feel I'm close to the solution but I don't know what am I doing wrong.

有人可以帮我弄清楚我需要验证文件的什么内容吗?

Can someone help me figuring out what am I missing to make the file verified?

PS;证书来自SSL证书(GoDaddy),而bundleCertificate.crt是GoDaddy捆绑包证书.

PS; The certs are from an SSL certificate (GoDaddy) and the bundleCertificate.crt is the GoDaddy bundle certificate.

推荐答案

我设法对文件进行了签名.令人怀疑,我接近最终解决方案.这是完整的代码.

I managed to sign the file. As suspected, I was close to the final solution. Here's the complete code.

public byte[] signMobileConfig(byte[] mobileconfig) 
        throws CertificateEncodingException, PEMException, FileNotFoundException, IOException, CertificateException, OperatorCreationException, CMSException {
    Security.addProvider(new BouncyCastleProvider());

    X509CertificateHolder caCertificate = loadCertfile();

    JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
    X509Certificate serverCertificate = certificateConverter.getCertificate(loadSigner());

    PrivateKeyInfo privateKeyInfo = loadInKey();
    PrivateKey inKey = new JcaPEMKeyConverter().getPrivateKey(privateKeyInfo);
    ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(inKey);

    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    JcaDigestCalculatorProviderBuilder digestProviderBuilder = new JcaDigestCalculatorProviderBuilder().setProvider("BC");
    JcaSignerInfoGeneratorBuilder generatotBuilder = new JcaSignerInfoGeneratorBuilder(digestProviderBuilder.build());

    generator.addSignerInfoGenerator(generatotBuilder.build(sha1Signer, serverCertificate));
    generator.addCertificate(new X509CertificateHolder(serverCertificate.getEncoded()));
    generator.addCertificate(new X509CertificateHolder(caCertificate.getEncoded()));

    CMSProcessableByteArray bytes = new CMSProcessableByteArray(mobileconfig);
    CMSSignedData signedData = generator.generate(bytes, true);

    return signedData.getEncoded();
}

这是我加载文件的方式:

And here's how I load the files:

public X509CertificateHolder loadSigner() throws FileNotFoundException, IOException {
    InputStream inputStream = externalResourcesFacade.getResourceAsStream("path/to/.crt");
    PEMParser parser = new PEMParser(new InputStreamReader(inputStream));
    return (X509CertificateHolder) parser.readObject();
}

public PrivateKeyInfo loadInKey() throws FileNotFoundException, IOException {
    InputStream inputStream = externalResourcesFacade.getResourceAsStream("path/to/.key");
    PEMParser parser = new PEMParser(new InputStreamReader(inputStream));
    return (PrivateKeyInfo) parser.readObject();
}

public X509CertificateHolder loadCertfile() throws FileNotFoundException, IOException {
    InputStream inputStream = externalResourcesFacade.getResourceAsStream("path/to/.crt");
    PEMParser parser = new PEMParser(new InputStreamReader(inputStream));
    return (X509CertificateHolder) parser.readObject();
}

这篇关于复制OpenSSL命令以使用Java对文件进行签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆