I am new to the security side of Java and stumbled across this library called BouncyCastle. But the examples that they provide and the ones out on the internet ask to use
return new PKCS10CertificationRequest("SHA256withRSA", new X500Principal(
"CN=Requested Test Certificate"), pair.getPublic(), null, pair.getPrivate()
But when I use PKCS10CertificationRequest, it looks like it is deprecated. So I started looking at another method where I use CertificationRequest class. But I am really confused, the constructor does not take the same parameters instead it takes CertificationRequestInfo class which I am not sure how to fill up.
CertificationRequest request = new CertificationRequest(...);
It would be awesome if someone could help me figure out how to make a CSR so that I can send it to the server for getting it signed.
With the recent versions of BouncyCastle it is recommended to create the CSR using the org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder class.
You can use this code snipppet:
KeyPair pair = generateKeyPair();
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
new X500Principal("CN=Requested Test Certificate"), pair.getPublic());
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
ContentSigner signer = csBuilder.build(pair.getPrivate());
PKCS10CertificationRequest csr = p10Builder.build(signer);
It's really simmilar to Jcs's answer, it is just a little bit supplemented.
Dont forget to add:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
And the csr generate:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
keyPairGenerator.initialize(4096);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
new X500Principal("OU=Try, C=US## Heading ##"), keyPair.getPublic());
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
ContentSigner signer = csBuilder.build(keyPair.getPrivate());
PKCS10CertificationRequest csr = p10Builder.build(signer);
JcaPEMWriter jcaPEMWriter = new JcaPEMWriter(new FileWriter("cert/test.csr"));
jcaPEMWriter.writeObject(csr);
jcaPEMWriter.close();
I think a useful link
Related
I am trying to add Key Usage to certificateSigningInfo in Java without using BouncyCastle. I have the following method which will create certificateSigningInfo that can be further signed to create PKCS#10:
public static byte[] createCertificationRequestInfo(X500Name x500Name, PublicKey publicKey) throws IOException {
final DerOutputStream der1 = new DerOutputStream();
der1.putInteger(BigInteger.ZERO);
x500Name.encode(der1);
der1.write(publicKey.getEncoded());
// der encoded certificate request info
final DerOutputStream der2 = new DerOutputStream();
der2.write((byte) 48, der1);
byte[] toReturn = der2.toByteArray();
der2.close();
return toReturn;
}
I am trying to add Key Usage with adding the following:
KeyUsageExtension ku = new KeyUsageExtension();
ku.set(KeyUsageExtension.NON_REPUDIATION, true);
ku.set(KeyUsageExtension.KEY_ENCIPHERMENT, true);
ku.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
ku.encode(der1);
The certificateSigningInfo is created but it can't be validate as it has some missing values...
For example, the following CSR is created:
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIErDCCApQCAQAwWjENMAsGA1UEBhMEVGVzdDENMAsGA1UECBMEVGVzdDENMAsGA1UEBxMEVGVz
dDENMAsGA1UEChMEVGVzdDENMAsGA1UECxMEVGVzdDENMAsGA1UEAxMEVGVzdDCCAiEwDQYJKoZI
hvcNAQEBBQADggIOADCCAgkCggIAr11wXkShGHeEVRxl1K4D/7Ow8uIgVro35h/WMBKl5UWOEqBc
ajTnU9AMN+u/rVa5uRt8HcHhWF8Y4RIMoNxlMuxBu36UbxKBnPza8Y1/Dbn0HGwzematfnFYS7B7
HdyVoj6yRcSo2tM/p8bmUGpxr1NSXsEtbxVINFhuyMZnwMpuVUsqTgB58Uo/+sjGtIxDVkLaMNs4
d/HCe2rwb5rYhkvAEgXtAtoWtDD9PPZTpxhKqO+cMYGZ0HqwFyQEu687ONUpVlA068DsgzwM6oh5
w3y2OJ8PiCXW+ojqxGr5mm7ig//mbgkk7QiwoZ3taYoqAdRfGlQsOZsVzHPzAIH84CHlF2LMRcIO
M8dA3eQSopjPDPOZixo8PGQ/cYtQPgyBVGmiQt/93JQ/BAypu9olO70y91nd+cEsEzoZdGkuFnTR
KVT67ye0GnxFik6Y/VJxpE36NPbofOXVRxy8jbazJGg/AzETAGmkKXoNAbzqvVCaV2zeAOZZmTFx
rgjwQxvgW2oxpv5SCBDxtsH+/JpuqEtg5y3jzLFuibSmGs6qNDATEDIG1F1Xl0+1I6ygIE+tcycI
m/9SmlIX9UsiSEvSJe0kZOwOIrByzYhezeXdbgSHiD2WiuMe1XvXJBkqpV0wuwhw74vRKAJtz3vC
n1DNVBmBWMPWfxlVczG+HwgLBSECAwEAATAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQENBQAD
ggIBAHCEHA47S0jO7AXvF7SDXtPPV2zlgUFtvCx0DfRerElYcmQFg5ylspfvkbQnlUFOcpKgoi1/
Kgq5vchLjKVEJPJK9066NsNTRy1Ayt4f3Ne7yQ46cnrL729x7TLUcWijDgmfJE/Cp4eC0qTF87mH
rYeOK0+1azki0r6/ToM9EliDU497Tsl2CWmAJlP+hkWQRa80uPFXkEV+UH0vQwOc8mf/aW+q3LHf
BXvPHcH3J9lPtDHMZgKav7Vi4sFU8tlCzm7QE6/jU49BN+Ptgp34k8Hw+VV+4lpZX2QpkDMvaPg5
Zd7LYNGhayP//EevCftiliWsNJSHa8aA6zqYvsTnBoEPFPL4sVfXsWp18AbK294WhF5vIe+8AFks
RHMLE+Nl13SXO3wHlNDT5jXKUGFmbCOASsUjyrpfQcwVMJ0/muAX43r6zo2YatZKgmCtVrBtKVuE
U7KMJW2aEDO7ML7+47VER8r1LYWSt96OY/9Pre+UehMuDloUC5B9nSf5TKyCShnzxXoNAE7izr2A
l3x9O071c9d/pRKjUBu9Q/IrSFT/blg94zGov+9FplcXc2Ygnblt5UNjAs5XcoC6ckhGPkrcZbw6
3Qk5R9TTJGX9wpzKTFPWJF735TaFqkJNwn1U5kTKWCTgbGUi3U98gTCCV4OkeT+Fo+pWuOqz5NV5
Q778
-----END NEW CERTIFICATE REQUEST-----
Any help is appreciated.
PKCS10 type CertificationRequestInfo can't directly contain an Extension, or even Extensions (which is SEQUENCE OF Extension). Instead it can contain Attributes which is SET OF Attribute each of which is SEQUENCE of OID and SET OF values constrained by a notional InfoSet, or in the old syntax ANY DEFINED BY --metaspec. One possible Attribute is PKCS9 5.4.2 extensionRequest which does contain Extensions which can include the one for KeyUsage.
Thus to add this to a PKCS10 you need something like the following. And as long as you are using the undocumented and possibly unreliable sun.security classes, there is one for PKCS10 that replaces most of the code you posted.
import sun.security.pkcs.*;
import sun.security.pkcs10.*; // separate in j8 (and later? not checked)
import sun.security.util.*;
import sun.security.x509.*;
// dummy setup; replace as appropriate
X500Name name = new X500Name("O=Widgets Inc, CN=testcert");
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(1024); KeyPair pair = gen.generateKeyPair();
KeyUsageExtension ku = new KeyUsageExtension();
ku.set(KeyUsageExtension.NON_REPUDIATION, true);
ku.set(KeyUsageExtension.KEY_ENCIPHERMENT, true);
ku.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
CertificateExtensions exts = new CertificateExtensions();
exts.set(KeyUsageExtension.IDENT,ku);
PKCS10Attribute extreq = new PKCS10Attribute (PKCS9Attribute.EXTENSION_REQUEST_OID, exts);
PKCS10 csr = new PKCS10 (pair.getPublic(), new PKCS10Attributes (new PKCS10Attribute[]{ extreq }));
Signature signer = Signature.getInstance("SHA256withRSA"); // or adapt to key
signer.initSign(pair.getPrivate());
csr.encodeAndSign(name, signer);
// dummy output; replace
FileOutputStream out = new FileOutputStream ("SO49985805.der");
out.write(csr.getEncoded()); out.close();
I have recently implemented digital signing and validation of office documents using the apache POI library. I am now looking to add verification to this so I can prove that the document was signed by a trusted user. I have tried the following code but with no success I think as the call to "getSigningCertificateChain" is empty but im not sure how to get this to load properly so the signature will be there? this is my current code:
pkg = OPCPackage.open(Dir, PackageAccess.READ);
sic = new SignatureConfig();
sic.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(sic);
isValid = si.verifySignature();
X509Certificate x509a = (X509Certificate) sic.getSigningCertificateChain().get(0);
FileInputStream fin = new FileInputStream("C:\myCer.cer");
CertificateFactory f = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)f.generateCertificate(fin);
PublicKey pk = certificate.getPublicKey();
x509a.verify(pk);
anyone had any luck with implementing this.
You have to select the certificate from the chain based on the issuer Common Name = {myCer.cer} Common Name, then try to verify it
PublicKey pk = selectedIssuedCertificate.getPublicKey();
x509a.verify(pk);
I hope this could help
There are two validate methods in the TimeStampToken class (bctsp-jdk16-1.46.jar), one of them is deprecated.
The deprecated method uses a X509Certificate as argument, and that's quite easy to create.
InputStream inPFX = getClass().getClassLoader().getResourceAsStream("tsp.cer");
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inPFX);
// The validate method just takes the X509Certificate object
token.validate(cert, "BC");
The new method uses a SignerInformationVerifier object. I found a way to create a SignerInformationVerifier (not sure it's the right way), but I still need a X509CertificateHolder object.
How do I create the X509CertificateHolder from a file on the filesystem (*.cer file)
Is this the correct way to create a SignerInformationVerifier to validate the TimeStampToken?
My current code looks like this:
TimeStampToken token = new TimeStampToken(new CMSSignedData(response));
X509CertificateHolder x = // HOW TODO THIS?
// create the SignerInformationVerifier object
DigestAlgorithmIdentifierFinder daif = new DefaultDigestAlgorithmIdentifierFinder();
DigestCalculatorProvider dcp = new BcDigestCalculatorProvider();
SignerInformationVerifier siv = new BcRSASignerInfoVerifierBuilder(daif, dcp).build(x509ch);
// use the new validate method
token.validate(siv);
Try this
TimeStampToken token = new TimeStampToken(new CMSSignedData(response));
InputStream in = new FileInputStream("tsp.cer");
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) factory.generateCertificate(in);
//RSA Signature processing with BC
X509CertificateHolder holder = new X509CertificateHolder(cert.getEncoded());
SignerInformationVerifier siv = new BcRSASignerInfoVerifierBuilder(new DefaultDigestAlgorithmIdentifierFinder(), new BcDigestCalculatorProvider()).build(holder);
//Signature processing with JCA and other provider
//X509CertificateHolder holderJca = new JcaX509CertificateHolder(cert);
//SignerInformationVerifier sivJca = new JcaSimpleSignerInfoVerifierBuilder().setProvider("anotherprovider").build(holderJca);
token.validate(siv);
Take a look at Verifying a SignerInformation object section of BC Version 2 APIs documentation for additional information about signature verification with BC API.
You are creating the SignerInformationVerifier in the right way, you can find attached at the sample code another way to create the SignerInformationVerifier for a JCA/JCE provider based solution.
I have an X509CertificateObject, a matching RSAPublicKey and managed to create a byte array containing a valid digital certificate for some message object also as a byte array.
Unfortunately the system I'm building upon only accepts CMSSignedData objects as input.
How do I convert my basic building blocks into such a valid CMSSignedData object?
Background: I'm experimenting with Java Bouncy Castle RSA blind signatures according to this example (digest is SHA512) and need to feed the result into the standard signature processing.
First, you'll probably want to sign your data with a private key. The idea being that the signature should be something only you can create. One you get that the rest should be as follows:
X509Certificate signingCertificate = getSigningCertificate();
//The chain of certificates that issued your signing certificate and so on
Collection<X509Certificate> certificateChain = getCertificateChain();
PrivateKey pk = getPrivateKey();
byte[] message = "SomeMessage".getBytes();
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
certificateChain.add(signingCertificate);
generator.addCertificates(new CollectionStore(certificateChain));
JcaDigestCalculatorProviderBuilder jcaDigestProvider = new JcaDigestCalculatorProviderBuilder();
jcaDigestProvider.setProvider(new BouncyCastleProvider());
JcaSignerInfoGeneratorBuilder singerInfoGenerator = new JcaSignerInfoGeneratorBuilder(jcaDigestProvider.build());
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
AsymmetricKeyParameter privateKeyParam = PrivateKeyFactory.createKey(pk.getEncoded());
ContentSigner cs = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(privateKeyParam);
SignerInfoGenerator sig = singerInfoGenerator.build(cs, signingCertificate);
generator.addSignerInfoGenerator(sig);
CMSSignedData data = generator.generate(new CMSProcessableByteArray(message), true);
I want to generate a simple CMS signature using bouncycastle.
This code works!
Security.addProvider(new BouncyCastleProvider());
String password = "123456";
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream("c:/cert_123456.p12"), password.toCharArray());
String alias = (String)ks.aliases().nextElement();
PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray());
Certificate[] chain = ks.getCertificateChain(alias);
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
generator.addSigner(key, (X509Certificate)chain[0], CMSSignedDataGenerator.DIGEST_SHA1);
ArrayList list = new ArrayList();
for (int i = 0; i < chain.length; i++) {
list.add(chain[i]);
}
CertStore chainStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(list), "BC");
generator.addCertificatesAndCRLs(chainStore);
CMSProcessable content = new CMSProcessableByteArray("test".getBytes());
CMSSignedData signedData = generator.generate(content, false, "BC");
byte[] pk = signedData.getEncoded();
But, how to add signed attributes?
I want to remove default signed attributes and add signature-policy-identifier.
Articles are very welcome.
First of all you appear to be using constructs that are deprecated in the latest versions of Bouncy Castle. To add authenticated/signed attributes you have to package them into an AttributeTable Signed attributes are added to the signer like so:
ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(new ASN1ObjectIdentifier("1.2.840.113549.1.7.1"))));
signedAttributes.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(digestBytes))));
signedAttributes.add(new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(signingDate))));
AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
Then use it in one of the addSigner methods. As I already mentioned in the beginning this method is deprecated and you are encouraged to use Generators and Generator Builders. Here's a short example:
/* Construct signed attributes */
ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(new ASN1ObjectIdentifier("1.2.840.113549.1.7.1"))));
signedAttributes.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(digestBytes))));
signedAttributes.add(new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(signingDate))));
AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
signedAttributesTable.toASN1EncodableVector();
DefaultSignedAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator(signedAttributesTable);
/* Build the SignerInfo generator builder, that will build the generator... that will generate the SignerInformation... */
SignerInfoGeneratorBuilder signerInfoBuilder = new SignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());
signerInfoBuilder.setSignedAttributeGenerator(signedAttributeGenerator);
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
JcaContentSignerBuilder contentSigner = new JcaContentSignerBuilder("SHA1withRSA");
contentSigner.setProvider("BC");
generator.addSignerInfoGenerator(signerInfoBuilder.build(contentSigner.build(this.signingKey), new X509CertificateHolder(this.signingCert.getEncoded())));
ArrayList<X509CertificateHolder> signingChainHolder = new ArrayList<X509CertificateHolder>();
Iterator i = this.signingChain.iterator();
while (i.hasNext()) {
X509CertificateObject cert = (X509CertificateObject)i.next();
signingChainHolder.add(new X509CertificateHolder(cert.getEncoded()));
}
generator.addCertificates(new JcaCertStore(signingChainHolder));
generator.generate(new CMSAbsentContent(), "BC").getEncoded();
It's quite bulky and probably doesn't work yet (I'm in the process of writing it and stumbled upon your question while researching some stuff), especially the signingDate part, it probably has to be new DERSet(new Time(new Date)) (update: it works with DERUTCTime).
A bit of offtopic: I still can't get my head around the difference between Signed and Authenticated attributes, Bouncy Castle has got both DefaultAuthenticatedAttributeTableGenerator, DefaultSignedAttributeTableGenerator classes which work perfectly well with Signers. There seem to be some minor differences between the two in regards to signingTime, SignedAttributes adds the signingTime by default if not present. The RFCs mention both attribute types, but I couldn't find anything definite.