使用Java将外部PKCS1字节数组和证书添加到CMS容器 [英] Adding external PKCS1 byte array and Certificate to CMS container with Java

查看:213
本文介绍了使用Java将外部PKCS1字节数组和证书添加到CMS容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We have client applications (Applets and Silverlight) that create a PKCS1 v2.1 digital signature. The digital signature is created as PKCS1 since the original content is not downloaded to the client, only the contents' hash is sent to the client to conserve bandwidth.

我们正在尝试创建PKCS7 / CMS容器服务器端,根据信息来自这篇文章

We are attempting to create a PKCS7/CMS container server side, based on the information from this post:


  1. 阅读证书并加​​载为X509Certificate类型

  2. 阅读PKCS1签名为base64并加载为字节数组

  3. 实例化新的ASN1ObjectIdentifier并设置PKCS1 OID(1.2.840.113549.1.1)

  4. 创建新的CMSTypedData CMSProcessableByteArray,使用asn1 object和signare byte [] as parameters

  5. 创建新的CMSSignedGenerator并添加证书

  6. 使用CMSTypedData类型创建新的CMSSignedData作为分离的签名

  1. Reading certificate and loading as X509Certificate type
  2. Reading PKCS1 signature as base64 and loading as byte array
  3. Instantiating new ASN1ObjectIdentifier and setting PKCS1 OID (1.2.840.113549.1.1)
  4. Creating new CMSTypedData CMSProcessableByteArray, using asn1 object and signare byte[] as parameters
  5. Create new CMSSignedGenerator and add certificates
  6. Create new CMSSignedData as detached signature using CMSTypedData type

然而,当得到t时o步骤5和6的事情中断,因为BC CMSSignedGenerator和CMSSignedData类不支持添加没有私钥的签名者:

However, when getting to steps 5 and 6 things break, as the BC CMSSignedGenerator and CMSSignedData classes do not support adding signers without the private key:

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,但这似乎也不起作用。

Any ideas on how to complete CMS container? Perhaps using AttributeTable to add muliple OID's for time stamps, etc., but that doesn't seem to work either.

推荐答案

我在查看此参考项目 https://code.google.com/p/j4ops/ <后找到答案/ A>。本指南也是一个很大的帮助,虽然它专门处理使用iText的PDF,它使用BC来自加密操作: http:/ /itextpdf.com/book/digitalsignatures20130304.pdf 。诀窍是通过实现使用符号(byte [] toEncrypt)方法的签名者接口将签名操作委托给外部提供者(PKCS11,PKCS12等)。通过这种方式,可以设置提供程序,然后只需调用sign方法,并保留有关如何签署提供程序本身的实现细节。

I found the answer after looking at this reference project https://code.google.com/p/j4ops/. This guide was also a big help although it deals specifically with PDFs using iText which use BC from crypto operations: http://itextpdf.com/book/digitalsignatures20130304.pdf. The trick is to delegate the signing operation to an external provider (PKCS11, PKCS12, etc) by implementing a Signer interface that uses a sign(byte[] toEncrypt) method, for example. This way, the provider can be set and then just call the sign method and leave the implementation details on how to sign to the provider itself.

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

Bouncy Castle uses a CMSSignedDataGenerator class with a SignerInf internal class to build the CMS container and the signer information, respectively. So the trick is to build a SignerInf object that doesn't need the private key, as sign() operation should be delegated to the provider. The private key may not even be available particularly when using smart cards. Additionally, the information that needs to be added as signed attributes and/or unsigned attributes needs to be considered when signing the hash and when building the CMS container. So these are the basic steps to solve the problem:

// 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();

这篇关于使用Java将外部PKCS1字节数组和证书添加到CMS容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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