复制OpenSSL命令以使用Java对文件进行签名 [英] Replicate OpenSSL command to sign a file in 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屋!