How to load and modify .cer file into memory - java

The following code loads test.cer file (Which is X509 Certificate) into memory. Is that possible to modify its fields when it is now in the memory, right? It is easy to output any field for example load.getPublicKey() but I want to change the first byte from the public key and output it again after changing. How would I do that?
File f= new File("Users/Desktop/JavaFolder/test.cer");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
while (in.available() > 0) {
Certificate load = cf.generateCertificate(in);
}
in.close();

After you have the Certificate:
Certificate cert = ....
PublicKey publicKey = cert.getPublicKey();
byte[] originalPublicKey = publicKey.getEncoded();
byte[] modifiedPublicKey = java.util.Arrays.copyOf(originalPublicKey , originalPublicKey .length);// make a copy
modifiedPublicKey[0] = !modifiedPublicKey[0]; // modify something
print(originalPublicKey); // your "print" method - implement it how you like it e.g., Arrays.toString(originalPublicKey)
print(modifiedPublicKey ); // your "print" method - implement it how you like it e.g., Arrays.toString(modifiedPublicKey)
See the javadoc reference
java.security.PublicKey
java.security.cert.Certificate
java.util.Arrays

Related

How to post data with .pem file certificate in java

I have a requirement for slate integration. I have a code for posting data but I want it to convert into java. Below is the code for reference:
'''string host = #url;
string certName = #"myfile.pfx"; // i am having .pem file
string password = #"password"; // no password
var certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(certName,
password);
System.Net.ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
var req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(host);
req.PreAuthenticate = true;
req.Credentials = new System.Net.NetworkCredential("username", "");
req.ClientCertificates.Add(certificate);
req.Method = "POST";
req.ContentType = "text/xml";
string postData = "<hello>world</hello>";
byte[] postBytes = System.Text.Encoding.UTF8.GetBytes(postData);
req.ContentLength = postBytes.Length;
req.GetRequestStream().Write(postBytes, 0, postBytes.Length);
req.GetRequestStream().Close();
var resp = req.GetResponse();'''
Please help in converting c code to java code or in generating a certificate from .pem file. I have checked many links in google but it's not working for me. It is throwing incomplete data or empty data while generating certificate from .pem file.
Thanks in advance,
If you want read the certificate you can use this below java code.
CertificateFactory fact = CertificateFactory.getInstance("X.509");
FileInputStream is = new FileInputStream (pemfilepath);
X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
PublicKey key = cer.getPublicKey();
If you want something else let me know

Generate valid CMS Signature file adding external PKCS#1 with Java

I'm generating CMS signature files with external PKCS#1 based on this thread.
The first step is obtain the signed attributes from the original file to be signed in external application which is returning PKCS#1 byte array.
Then build standard org.bouncycastle.cms.SignerInfoGenerator with original file hash, signed data (PKCS#1) and certificate to add to CMS, and finally create the attached signature.
But when i'd tried to validate it using this code:
String originalFile = "aG9sYQ0KYXNkYXMNCg0KYWZzDQo=";
String cmsSignedFile = "MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBg...j2Dwytp6kzQNwtXGO8QbWty1lOo8oYm+6LR8EWba3ikO/m9ol/G808vit9gAAAAAAAA==";
byte[] signedByte = DatatypeConverter.parseBase64Binary(cmsSignedFile);
Security.addProvider(new BouncyCastleProvider());
CMSSignedData s = new CMSSignedData(new CMSProcessableByteArray(DatatypeConverter.parseBase64Binary(originalFile)), signedByte);
SignerInformationStore signers = s.getSignerInfos();
SignerInformation signerInfo = (SignerInformation)signers.getSigners().iterator().next();
FileInputStream fis = new FileInputStream("C:/myCertificate.cer");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificates(fis).iterator().next();
boolean result = signerInfo.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert.getPublicKey()));
System.out.println("Verified: "+result);
I get Verified: false
I'm adding Content Type, Signing time, Message digest and OCSP as signed attributes and TSP Token as unsigned attribute (I'm not sure if this is right).
I'm also trying to recover data from CMS signature, using the code below:
//load cms signed file with attached data
CMSSignedData cms = new CMSSignedData(FileUtils.readFileToByteArray(new File("C:/tmp/tempFile1864328163858309463.cms")));
System.out.println(cms.getSignerInfos().getSigners().iterator().next().getDigestAlgorithmID().getAlgorithm().getId());
System.out.println(Hex.encodeHexString(cms.getSignerInfos().getSigners().iterator().next().getSignature()));
//recover signer certificate info
Store certs = cms.getCertificates();
Collection<X509CertificateHolder> col = certs.getMatches(null);
X509CertificateHolder []h1 = col.toArray(new X509CertificateHolder[col.size()]);
X509CertificateHolder firmante = h1[0];
System.out.println(firmante.getSubject());
System.out.println(h1[1].getSubject());
SignerInformation sinfo = cms.getSignerInfos().getSigners().iterator().next();
//recover OCSP information
//THIS FAILS :(
// Store infocspbasic = cms.getOtherRevocationInfo(OCSPObjectIdentifiers.id_pkix_ocsp_basic);
// Object basic = infocspbasic.getMatches(null).iterator().next();
//recover signing time
if (sinfo.getSignedAttributes() != null) {
Attribute timeStampAttr = sinfo.getSignedAttributes().get(PKCSObjectIdentifiers.pkcs_9_at_signingTime);
ASN1Encodable attrValue = timeStampAttr.getAttrValues().getObjectAt(0);
final Date signingDate;
if (attrValue instanceof ASN1UTCTime) {
ASN1UTCTime time = ASN1UTCTime.getInstance(attrValue);
Date d = time.getDate();
System.out.println("ASN1UTCTime:" + d);
} else if (attrValue instanceof Time) {
signingDate = ((Time) attrValue).getDate();
} else if (attrValue instanceof ASN1GeneralizedTime) {
System.out.println("ASN1GeneralizedTimeASN1GeneralizedTime");
} else {
signingDate = null;
}
}
//recover timestamp TOken
//unsigned attributes are null :(
if (sinfo.getUnsignedAttributes() != null) {
Attribute timeStampAttr = sinfo.getUnsignedAttributes().get(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken);
for (ASN1Encodable value : timeStampAttr.getAttrValues().toArray()) {
TimeStampToken token = new TimeStampToken(new CMSSignedData(value.toASN1Primitive().getEncoded()));
System.out.println(token.getTimeStampInfo().getGenTime());
}
}
But I can't retrieve OCSP response nor TSP Token information. Additionally I've downloaded this viewer software to help verify it:
Any help would be very appreciated.
I found a project named j4sign which implements CMS signature with external PKCS#1. The link goes to the project's forum where I posted the code sample using their classes and the final correction to make the validation works.

Return .p12 file to client without creating keystore file

Is there any way to return a file to client with .p12 extension (base64 encoded string, that is later decoded on the client side and saved with .p12 extension) without storing it to PKCS12 keystore? I have code for creating root certificate, client certificate and setting keyentry to PKCS12 keystore bellow, but I don't want to have .p12 file on the file system, just to generate it and return it to client. Thanks!
Simplified code of creating root certificate:
public static void createRootCertificate(PublicKey pubKey, PrivateKey privKey) {
certGen.setSerialNumber(...);
certGen.setIssuerDN(...);
certGen.setNotBefore(...);
certGen.setNotAfter(...);
certGen.setSubjectDN(...);
certGen.setPublicKey(pubKey);
certGen.setSignatureAlgorithm("SHA1WithRSA");
// add extensions, key identifier, etc.
X509Certificate cert = certGen.generateX509Certificate(privKey);
cert.checkValidity(new Date());
cert.verify(pubKey);
}
The root certificate and its private key is saved to the trusted store after creating.
Than, in the service for generating client certificates, I read root certificate from trusted store and generate client ones:
public static Certificate createClientCertificate(PublicKey pubKey) {
PrivateKey rootPrivateKey = ... //read key from trusted store
X509Certificate rootCertificate = ... //read certificate from trusted store
certGen.setSerialNumber(...);
certGen.setIssuerDN(...); // rootCertificate.getIssuerDN ...
certGen.setNotBefore(...);
certGen.setNotAfter(...);
certGen.setSubjectDN(...);
certGen.setPublicKey(pubKey);
certGen.setSignatureAlgorithm("SHA1WithRSA");
// add extensions, issuer key, etc.
X509Certificate cert = certGen.generateX509Certificate(rootPrivateKey);
cert.checkValidity(new Date());
cert.verify(rootCertificate.getPublicKey(););
return cert;
}
Main class look like this:
public static void main(String[] args) {
// assume I have all needed keys generated
createRootCertificate(rootPubKey, rootPrivKey);
X509Certificate clientCertificate = createClientCertificate(client1PubKey);
KeyStore store = KeyStore.getInstance("PKCS12", "BC");
store.load(null, null);
store.setKeyEntry("Client1_Key", client1PrivKey, passwd, new Certificate[]{clientCertificate});
FileOutputStream fOut = new FileOutputStream("client1.p12");
store.store(fOut, passwd);
}
After the code above, I'm reading client1.p12 and I'm creating Base64 encoded response of that file. When I decode response on my client and save with .p12 extension everything works, I can import it to browser. Can this be done without storing it to file?
I have tried with:
store.setKeyEntry("Client1_Key", client1PrivKey, passwd, new Certificate[]{clientCertificate});
and after that:
Key key = store.getKey("Client1_Key", passwd);
but when encode key variable, send to client and than decode it and save with .p12 extension, browser say invalid or corrupted file.
Thanks in advance!
Simply use a ByteArrayOutputStream instead of FileOutputStream to store the p12:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
store.store(baos, passwd);
byte[] p12Bytes = baos.toByteArray();
String p12Base64 = new String(Base64.encode(p12Bytes));

How to load PKCS7 (.p7b) file in java

I have a pkcs7 file, and I want to load it and extract its contents.
I tried these two methods:
byte[] bytes = Files.readAllBytes(Paths.get("myfile.p7b"));
FileInputStream fi = new FileInputStream(file);
//Creating PKCS7 object
PKCS7 pkcs7Signature = new PKCS7(bytes);
or this
FileInputStream fis = new FileInputStream(new File("myfile.p7b"));
PKCS7 pkcs7Signature = new PKCS7(fis);
but I got IOException: Sequence tag error
So how can I load this .p7b file ?
Finally I did it with BouncyCastle library.
PKCS#7 is a complex format, also called CMS. Sun JCE has no direct support to PKCS#7.
This is the code that I used to extract my content:
// Loading the file first
File f = new File("myFile.p7b");
byte[] buffer = new byte[(int) f.length()];
DataInputStream in = new DataInputStream(new FileInputStream(f));
in.readFully(buffer);
in.close();
//Corresponding class of signed_data is CMSSignedData
CMSSignedData signature = new CMSSignedData(buffer);
Store cs = signature.getCertificates();
SignerInformationStore signers = signature.getSignerInfos();
Collection c = signers.getSigners();
Iterator it = c.iterator();
//the following array will contain the content of xml document
byte[] data = null;
while (it.hasNext()) {
SignerInformation signer = (SignerInformation) it.next();
Collection certCollection = cs.getMatches(signer.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder cert = (X509CertificateHolder) certIt.next();
CMSProcessable sc = signature.getSignedContent();
data = (byte[]) sc.getContent();
}
If you want to verify the signature of this PKCS7 file against X509 certificate, you must add the following code to the while loop:
// ************************************************************* //
// ********************* Verify signature ********************** //
//get CA public key
// Create a X509 certificat
CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
// Open the certificate file
FileInputStream fileinputstream = new FileInputStream("myCA.cert");
//get CA public key
PublicKey pk = certificatefactory.generateCertificate(fileinputstream).getPublicKey();
X509Certificate myCA = new JcaX509CertificateConverter().setProvider("BC").getCertificate(cert);
myCA.verify(pk);
System.out.println("Verfication done successfully ");

Extracting individual .cer certificate from a .p7b file in java

I am new to Cryptography and so please excuse me if you think this is a basic question
I have a .p7b file which I need to read and extract the individual public certificates i.e the .cer files and store it in the key store. I need not worry about persisting in the key store as there is already a service which takes in the .cer file as byte[] and saves that.
What i want to know is , how do i read the .p7b and extract the individual .cer file? I know that can be done via the openSSL commands, but i need to do the same in java. I need to also read the Issued By name as that will be used as a unique key to persist the certificate.
Thanks in advance
You can get the certificates from a PKCS#7 object with BouncyCastle. Here is a quick code sample:
public Collection<X59Certificate> getCertificates(String path) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
CMSSignedData sd = new CMSSignedData(new FileInputStream(path));
X509Store store = sd.getCertificates("Collection", "BC");
Collection<X509Certificate> certificates = store.getMatches(X509CertStoreSelector.getInstance(new X509CertSelector()));
return certificates;
}
Note that a PKCS#7 may contain more than one certificate. Most of the time it includes intermediate certification authority certificates required to build the certificate chain between the end-user certificate and the root CA.
I was successfully able to read the individual .X509 certificates from the p7b files. Here are the steps
First step includes, getting a byte[] from the java.io.File. The steps include to remove the -----BEGIN PKCS7----- and -----END PKCS7----- from the file, and decode the remaining base64 encoded String.
BufferedReader reader = new BufferedReader(new FileReader(file));
StringBuilder cerfile = new StringBuilder();
String line = null;
while(( line = reader.readLine())!=null){
if(!line.contains("PKCS7")){
cerfile.append(line);
}
}
byte[] fileBytes = Base64.decode(cerfile.toString().getBytes());
The next step is to use the BouncyCastle api to parse the file
CMSSignedData dataParser = new CMSSignedData(trustBundleByte);
ContentInfo contentInfo = dataParser.getContentInfo();
SignedData signedData = SignedData.getInstance(contentInfo.getContent());
CMSSignedData encapInfoBundle = new CMSSignedData(new CMSProcessableByteArray(signedData.getEncapContentInfo().getContent().getDERObject().getEncoded()),contentInfo);
SignedData encapMetaData = SignedData.getInstance(encapInfoBundle.getContentInfo().getContent());
CMSProcessableByteArray cin = new CMSProcessableByteArray(((ASN1OctetString)encapMetaData.getEncapContentInfo().getContent()).getOctets());
CertificateFactory ucf = CertificateFactory.getInstance("X.509");
CMSSignedData unsignedParser = new CMSSignedData(cin.getInputStream());
ContentInfo unsginedEncapInfo = unsignedParser.getContentInfo();
SignedData metaData = SignedData.getInstance(unsginedEncapInfo.getContent());
Enumeration certificates = metaData.getCertificates().getObjects();
// Build certificate path
while (certificates.hasMoreElements()) {
DERObject certObj = (DERObject) certificates.nextElement();
InputStream bin = new ByteArrayInputStream(certObj.getDEREncoded());
X509Certificate cert = (X509Certificate) ucf.generateCertificate(bin);
X500Name x500name = new JcaX509CertificateHolder(cert).getSubject();
RDN cn = x500name.getRDNs(BCStyle.CN)[0];
}
The above steps are working fine, but i am sure there are other solutions with less lines of code to achieve this. I am using bcjdk16 jars.

Categories