复制 OpenSSL 命令以在 Java 中签署文件
Replicate OpenSSL command to sign a file in Java
我需要签署一个文件,到目前为止我已经使用了工作正常的 openssl
命令(文件已签署和验证)。
openssl smime -sign -in unsigned.mobileconfig -out signed.mobileconfig -signer myCrtFile.crt -inkey myKeyFile.key -certfile bundleCertificate.crt -outform der -nodetach
但现在我需要在运行时执行此操作,因此我需要以编程方式对文件进行签名。我正在使用 BouncyCastle
但我愿意切换到另一个库。
我不擅长证书,更不擅长 BouncyCastle
。这是我带来的。
openssl命令对应的文件如下:
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 文件)时,它显示 "The file is signed but could not be verified"。我觉得我接近解决方案,但我不知道我做错了什么。
有人可以帮我弄清楚我缺少什么来验证文件吗?
PS;证书来自 SSL 证书 (GoDaddy),bundleCertificate.crt
是 GoDaddy 捆绑证书。
我成功签署了文件。不出所料,我已经接近最终解决方案了。这是完整的代码。
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();
}
这是我加载文件的方式:
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
命令(文件已签署和验证)。
openssl smime -sign -in unsigned.mobileconfig -out signed.mobileconfig -signer myCrtFile.crt -inkey myKeyFile.key -certfile bundleCertificate.crt -outform der -nodetach
但现在我需要在运行时执行此操作,因此我需要以编程方式对文件进行签名。我正在使用 BouncyCastle
但我愿意切换到另一个库。
我不擅长证书,更不擅长 BouncyCastle
。这是我带来的。
openssl命令对应的文件如下:
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 文件)时,它显示 "The file is signed but could not be verified"。我觉得我接近解决方案,但我不知道我做错了什么。
有人可以帮我弄清楚我缺少什么来验证文件吗?
PS;证书来自 SSL 证书 (GoDaddy),bundleCertificate.crt
是 GoDaddy 捆绑证书。
我成功签署了文件。不出所料,我已经接近最终解决方案了。这是完整的代码。
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();
}
这是我加载文件的方式:
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();
}