当前位置: 首页 > 知识库问答 >
问题:

使用Java将外部PKCS1字节数组和证书添加到CMS容器

盛超
2023-03-14

我们有创建PKCS1 v2.1数字签名的客户端应用程序(Applets和Silverlight)。数字签名被创建为PKCS1,因为原始内容没有下载到客户端,只有内容的散列被发送到客户端以节省带宽。

我们正在尝试根据这篇文章中的信息创建一个 PKCS7/CMS 容器服务器端:

  1. 读取证书并加载为X509证书类型
  2. 将PKCS1签名读取为Bas64并加载为字节数组
  3. 实例化新的ASN1Object标识符并设置PKCS1 OID(1.2.840.113549.1.1)
  4. 使用asn1对象和Signare byte[]作为参数创建新的CMSTyedData CMSProcessableByteArray
  5. 创建新的CMSSignedDynamator并添加证书
  6. 使用CMSTyedData类型创建新的CMSSignedData作为分离签名

但是,当进入第5步和第6步时,事情会中断,因为BC CMSSignedDynamator和CMSSignedData类不支持在没有私钥的情况下添加签名者:

CMS创建:

    // Add BC to environment
    Security.addProvider(new BouncyCastleProvider());

    // Read certificate and convert to X509Certificate
    CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
    Path certPath = Paths.get("C:\\MyCertificate.cer");
    byte[] certData = Files.readAllBytes(certPath);
    InputStream in = new ByteArrayInputStream(certData);
    X509Certificate cert = (X509Certificate)certFactory.generateCertificate(in);

    // Add signer certificates to List and add them to store
    List<X509Certificate> certList = new ArrayList<X509Certificate>();
    certList.add(cert);
    Store certs = new JcaCertStore(certList);

    // Get signature in Base64, decode and convert to byte array
    // Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
    String signatureBase64 = "gjTbsD0vSOi6nMlRVbpTLRQ5j+g2h8iEH1DgQx93PDBuwzWT47urKxMAS+75dAhQrkreLt9TGZaDN85e5xEpIF12mK1G+AgCNc370I1bjxOvUU67IVxHkZ+IX8kzSiD2uNuQtk3IrwUqyL30TIo+LDAXmY1AQVZwXAaOYG4bXxI=";
    BASE64Decoder decoder = new BASE64Decoder();
    byte[] signatureByte = decoder.decodeBuffer(signatureBase64);

    // Instantiate new ANS1ObjectIdentifier to identify PKCS1 signature
    ASN1ObjectIdentifier asn1OidPkcs1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1");

    // Table generator
    /*AttributeTable attrT = new AttributeTable();
    SimpleAttributeTableGenerator sAttrTGen = new SimpleAttributeTableGenerator();*/

    // Instantiate new CMSProcessable object
    CMSTypedData msg = new CMSProcessableByteArray(asn1OidPkcs1, signatureByte);

    // Instantiate new CMSSignedDataGenerator object
    CMSSignedDataGenerator gen = new CMSSignedDataGenerator();

    // ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").s
    gen.addCertificates(certs);
    CMSSignedData sigData = gen.generate(msg, false);


    // BASE64Encoder encoder = new BASE64Encoder();
    new File("C:\\MyCMS.p7s");
    FileOutputStream fileOuputStream = new FileOutputStream("C:\\Users\\gregwerner\\Documents\\Archivos\\miFirma.p7s"); 
    fileOuputStream.write(sigData.getEncoded());
    fileOuputStream.flush();
    fileOuputStream.close();

}

关于如何完成CMS容器有什么想法吗?也许可以使用AttributeTable为时间戳等添加多个OID,但这似乎也不起作用。

共有1个答案

李俊雅
2023-03-14

我看了这个参考项目后找到了答案https://code.google.com/p/j4ops/.尽管本指南专门处理使用iText的PDF,这些PDF使用加密操作中的BC,但它也是一个很大的帮助:http://itextpdf.com/book/digitalsignatures20130304.pdf.技巧是通过实现使用sign(byte[]toEncrypt)方法的Signer接口,将签名操作委托给外部提供者(PKCS11、PKCS12等)。这样,就可以设置提供者,然后调用sign方法,并将如何签名的实现细节留给提供者本身。

Bouncy Castle 使用 CMSSignedDataGenerator 类和 SignerInf 内部类分别构建 CMS 容器和签名者信息。因此,诀窍是构建一个不需要私钥的 SignerInf 对象,因为 sign() 操作应该委托给提供者。私钥甚至可能不可用,尤其是在使用智能卡时。此外,在对哈希进行签名和构建 CMS 容器时,需要考虑需要添加为签名属性和/或未签名属性的信息。因此,这些是解决问题的基本步骤:

// Build the items to encrypt, objects for method parameters would be obtained previously.
byte[] toEncrypt = externalSignerInfoGenerator.getCmsBytesToSign(hash, 
            signingTime, 
            PKCSObjectIdentifiers.data, 
            x509Cert, 
            timeStampToken, 
            ocsp);
// The externalSignerInfoGenerator.getCmsBytesToSign is a method from a re implemention of the 
// SignerInf inner class from CMSSignedDataGenerator and is used to get a byte array from an 
// org.bouncycastle.asn1.ASN1EncodableVector. To build the vector one should add attributes to
// their corresponding OID's using the org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers interface,
// for example:
ASN1EncodableVector signedAttrVector = buildSignedAttributes (hash, signingTime, contentType,
x509Cert, ocspResp);
// This would call the buildSignedAttributes method to build the signed attributes vector
ASN1EncodableVector signedAttrVector = new ASN1EncodableVector();
// Add CMS attributes
signedAttrVector.add (new Attribute(CMSAttributes.contentType, new DERSet (contentType)));
signedAttrVector.add (new Attribute (CMSAttributes.signingTime, new DERSet(new Time (signingTime))));
signedAttrVector.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(hash))));
// Not all attributes are considered in BC's CMSAttributes interface, therefore one would have to add 
// an additional step:
signedAttrVector.add(buildOcspResponseAttribute(ocspResp));
// This method would call buildOcspResponseAttribute to add the object as a PKCSObjectIdentifier
protected Attribute buildOcspResponseAttribute (byte[] ocspResp) throws IOException, CMSException {
    return new Attribute (PKCSObjectIdentifiers.id_aa_ets_revocationRefs, 
    new DERSet(DERUtil.readDERObject(ocspResp)));
}  

// Call sign method from provider, such as PKCS11, PKCS12, etc.
byte [] signature = getSignProvider().sign(toEncrypt);
// Now build standard org.bouncycastle.cms.SignerInfoGenerator with hash, signed data 
// and certificate to add to CMS, create attached or detached signature
// create signed envelope
CMSSignedData envdata = externalCMSSignedDataGenerator.generate(false);                
byte[] enveloped = envdata.getEncoded();
 类似资料:
  • 我检查了这个关于正确签名数据的问题,但它没有响应我的SCEP服务器的需求。我使用的代码来自EJBCA,但似乎没有向PKCS7签名数据添加证书。 当我使用工具解析签名数据时,我看到“证书”字段是“空的”。此外,当我尝试使用,我一无所获。 以下是我如何用Bouncy Castle签署我的数据(代码很多,但足以重现问题):

  • 问题内容: 我在java和cxf中有一个用客户端证书连接到WebServices的应用程序。 我从WebService所有者那里获得了证书 证书 证书 certificate.crt Trusted_ca.cer root_ca.cer 我直接将这个p12证书转换为java要求的有效jks密钥库时遇到问题。 我这样做: 但是此jks不起作用,使用此证书时我收到HTTP响应‘403:Forbidde

  • 问题内容: 我有这个字节数组: 现在,假定此字节数组的CRC校验和为0x60、0x0A。我希望Java代码重新创建此校验和,但是我似乎无法重新创建它。我尝试了crc16: 并使用Integer.toHexString()进行转换,但结果均不匹配正确的CRC。有人可以根据CRC公式指出我正确的方向。 问题答案: 请使用以下代码: 但是,您可能必须反转返回的CRC才能获得正确的字节序。我什至在这里测试

  • 什幺是数字证书和数字证书链 上一节说到SSL/TLS协议是为了解决三大风险而设计,第三点就是防止身份被冒充,防止身份被冒充的核心关键就是数字证书和数字证书链。下面”直白”的方式说下数字证书和数字证书链。 为了保证信息在传输中的安全和双方的身份不被冒充,HTTPS在建立安全链接阶段使用了公钥、私钥两把“钥匙”——非对称加密。非对称意思是:公钥加密的内容,只有私钥才能解密。私钥加密的内容,只有公钥才能

  • 我想使用swig从C附加到Javabyte[]。诀窍是在不调用GetByteArrayElements的情况下执行此操作,因为如果无法固定byte[],这将生成byte[]的副本。 没有swig,我们可以使用SetByteArrayArea轻松做到这一点-直接将字节数写入byte[]。swg的问题是: > 执行实际工作的代码在. cpp中-例如读取文件的内容并将其放入字符串fileContents