0

iText 的新用户试图在https://itextpdf.com/book/digitalsignatures中获取从示例 3.1 和代码示例 3.2 改编的示例代码

我在 FYI 下面包含了代码片段。

我让托管服务提供商.pfx从 GlobalSign 证书创建一个文件(他们不提供.p12文件)。他们发出了以下linux命令:

# openssl pkcs12 -export -out cert.pfx -inkey www.mydomain.com.key 
  -in ../certs/www.mydomain.com.crt -certfile ../certs/ca-bundle.crt

ca-bundle.crtGlobalSign 来自哪里。为了得到一个.p12,我只是将文件复制.pfx到一个带有.p12扩展名的新文件中。从我在网上看到的情况来看,人们之前已经这样做了(与 iText 无关)并且成功了,因为.pfx文件和.p12文件是二进制等价物。

要验证,可以在 linux 提示符下键入:

openssl pkcs12 -info -in /path/to/file/cert.pfx

然后它会要求输入密码,但没有,所以只需按 Enter,然后它会要求输入我输入的私人密码短语(例如myPrivateCertPassword),然后它会显示我的私人证书、GlobalSign 的公共证书和我的私钥。

现在是我感到困惑的地方。没有导入密码,所以我在 iText 中尝试了以下尝试(如下面的片段所示):

  ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), null);
  ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), "".toCharArray());

没有一个工作。第一个给出运行时错误:

java.io.IOException: PKCS12 key store mac invalid - wrong password or corrupted file.

第二个给出运行时错误:

java.lang.NoClassDefFoundError : org/bouncycastle/cert/X509CertificateHolder 

有什么想法可能是错的吗?

确切地说,ks.load()代码行中使用的密码来自哪里(GlobalSign?服务器托管公司?我?)。export key当我发出上述导出命令时,这是否称为?

提前感谢您的任何评论。

-------- 代码片段如下 ---------

public static final char[] PASS = "myPrivateCertPassword".toCharArray();   
public static final String CERTIFICATE_PATH = "/path/to/file/cert.p12";

在 main() 中:

BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance("pkcs12", provider.getName()); 
ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), null);
// ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), "".toCharArray()); // this also fails
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, CONSTANTS.PASS);
Certificate[] chain = ks.getCertificateChain(alias);
sign(userFile, userFile_signed, chain, pk, DigestAlgorithms.SHA256, 
   provider.getName(),CryptoStandard.CMS, "Test", "Ghent", null, null, null, 0);

外部主要():

public void sign(
String src,
String dest,
Certificate[] chain,
PrivateKey pk,
String digestAlgorithm,
String provider,
CryptoStandard subfilter,
String reason,
String location,
Collection<CrlClient> crlList,
OcspClient ocspClient, TSAClient tsaClient,
int estimatedSize)
throws GeneralSecurityException, IOException, DocumentException {
  // Creating the reader and the stamper
  PdfReader reader = new PdfReader(src);
  FileOutputStream os = new FileOutputStream(dest);
  PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
  // Creating the appearance
  PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
  appearance.setReason(reason);
  appearance.setLocation(location);
  appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
  // Creating the signature
  ExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
  ExternalDigest digest = new BouncyCastleDigest();
  MakeSignature.signDetached(appearance, digest, pks, chain,
  crlList, ocspClient, tsaClient, estimatedSize, subfilter);
 }

更新 1:

我通过如上所述导出创建了一个新的 cert.pfx 文件,但这次我输入了一个“导出密码”,as exportPassword,我将其插入为:

  ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), "exportPassword".toCharArray());

但这会产生一个新的运行时错误:

 java.io.IOException: exception decrypting data - java.security.InvalidKeyException: Illegal key size

我越来越近了吗?

更新 2:

我根据布鲁诺的评论安装了 JCE,现在我收到了这个错误:

java.lang.NoClassDefFoundError : org/bouncycastle/tsp/TimeStampTokenInfo

更新 3:

我还可以通过将 www.bouncycastle.org 中的 bcpkix-jdk15on-149.jar 添加到 /lib 目录来清除上述错误,并将以下内容添加到 java 程序中:

import org.bouncycastle.jce.provider.BouncyCastleProvider; // this was already there
import org.bouncycastle.tsp.TimeStampTokenInfo; // this is new and fixed the above error

现在我可以看到数字签名了!

更新 4:

对于那些感兴趣的人,请参阅我的后续帖子: iText:人们使用哪种类型的证书来在 Linux 上自动进行 PDF 签名?

4

0 回答 0