There is the same question here: Decode string with PKC7 in Java I tried the solution described there, but obviously it is a little outdated, because in the current bouncycastle library there is no org.bouncycastle.openssl.PEMReader class, but org.bouncycastle.openssl.PEMParser. and when i used it in the example:
PEMParser pr = new PEMParser(sr);
X509Certificate cert = (X509Certificate)pr.readObject();
i got an exception:
Exception in thread "main" java.lang.ClassCastException: class org.bouncycastle.asn1.cms.ContentInfo cannot be cast to class java.security.cert.X509Certificate
I would like just to ask someone to provide solution of decoding PKCS#7 with the current Bouncycastle library.
The Maven part for Bouncycastle looks like this
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.58</version>
</dependency>
This is the PKCS#7 that i am trying to decode:
-----BEGIN PKCS7-----
MIIC5wYJKoZIhvcNAQcCoIIC2DCCAtQCAQExADALBgkqhkiG9w0BBwGgggK8MIICuDCCAl6gAwIB
AgIQXCpspdawOszPHWPu6BzK7DAKBggqhkjOPQQDAjBAMQswCQYDVQQGEwJERTEUMBIGA1UEChML
U29mdHdhcmUgQUcxGzAZBgNVBAMTElFBIFRoaW4tRWRnZSBDQSBHMTAeFw0yMjA2MjIwNzM1MDJa
Fw0yNTA2MjIwNzM1MDJaMCUxIzAhBgNVBAMTGlJlcXVlc3RlZCBUZXN0IENlcnRpZmljYXRlMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjahV4/HclaS48gxI6ojGk1WZsBr+oS2PwAG5
abWG1ilmOGakfSoJt5exz3+vfbqX9Wewge7kE+2ehM3kyhLxtRLc9o2IbvbRsonyncIhb0SqJ+6j
oTK8b7Dd1XwTFNLMNpQK2trY6c0ScBrdJarPv0QKszlpJHpFCCjozlaExdFKeYINUzSN6UKMd9Kw
L6T/3QPOQSBLVAwKnBC8dZnxmoG8Nr0XOJE0FBDISnB/PkE70w8bTqquCCqdWInFZJkZog+QsYBu
LDZq5ODeoUfSrkfnrR1xudgS5/OYRsU5jfwU5h4D1bM1MSQAMseOalFO+Iv5tm4tszNF3HNwSn8N
KQIDAQABo4GJMIGGMBMGA1UdJQQMMAoGCCsGAQUFBwMCMBMGA1UdIwQMMAqACEhBtjq9T25cMAsG
A1UdDwQEAwIFoDBNBgNVHR8ERjBEMEKgQKA+hjxodHRwOi8vZHAuMzgucWEuZ28ubmV4dXNncm91
cC5jb20vY3JsL3FhX3RoaW4tZWRnZV9jYV9nMS5jcmwwCgYIKoZIzj0EAwIDSAAwRQIhALgVQ4GE
NDd3KkjDjDE1a3Kn5FzjTWVjDc4ZdCsJvm1yAiBHdeGu8Sklq57MM1eSMMS7C4KvAYepzPkM4/9s
vgRT8zEA
-----END PKCS7-----
PKCS7 and its successor CMS is a wide-ranging standard that includes many types of messages. Some of these messages can contain one or more (X.509) certificate(s). If your PKCS7/CMS is actually a SignedData containing certificate(s), you don't need BouncyCastle at all; you can directly read the certificate(s) with standard Java CertificateFactory
as described in the introductory section of the javadoc .
That is actually what the hacky code in the Q you link does; by putting a false PEM label of BEGIN/END CERTIFICATE on data that is in fact NOT a certificate, but actually a PKCS7/CMS SignedData containing a certificate, it causes the now-obsolete PEMReader code to call CertificateFactory internally. With more recent PEMParser that wouldn't work; you must parse it as PKCS7/CMS and then resolve it yourself. (Even 1.58 isn't exactly current, it's from 2017.) If you want to go that way, the following example reads the data from that Q (correctly labelled as BEGIN/END PKCS7, NOT faked as CERTIFICATE) and extracts the one cert:
String in = new String(Files.readAllBytes(Paths.get(args[0])) );
// import org.bouncycastle.asn1.* and ...cms.* (not superseded ...pkcs.*)
// and of course org.bouncycastle.openssl.PEMParser
@SuppressWarnings("resource") // I don't bother closing the PEMParser
ContentInfo ci = (ContentInfo) new PEMParser(new StringReader(in)).readObject();
if( !ci.getContentType().equals(CMSObjectIdentifiers.signedData) )
throw new Exception ("not SignedData"); // or other handling as suitable
SignedData sd = SignedData.getInstance( ci.getContent() );
// this takes the first/only cert and fails if none; could handle missing
// and/or loop over multiple looking for or selecting the desired one or ones
byte[] raw = ((ASN1Sequence)sd.getCertificates().getObjects().nextElement()) .getEncoded();
X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(raw));
System.out.println (cert.toString());
Numerous variations are possible depending on exactly what you need to handle.
Note SignedData.certs is an ASN.1 SET and arbitrarily ordered. If used for eg a rootlist this doesn't matter, but if used for a cert chain -- as many CAs did in ancient times -- the end-entity or 'leaf' cert, although logically first in the chain, may not be physically first in the PKCS7/CMS. In recent years CAs more often just use a sequence of (individual) PEM certs, which does preserve order -- and which CertificateFactory and keytool etc also handles.
Added: you now disclose you (also?) want the certificate in PEM form (the textlike form beginning -----BEGIN CERTIFICATE-----
and ending -----END CERTIFICATE-----
). This is trivial with Bouncy; just do
JcaPEMWriter w = new JcaPEMWriter (/*suitable Writer to a file or whatever */)
w.writeObject(cert);
w.close(); // or w.flush(); to keep underlying writer/stream open
or if you only need the PEM and aren't doing anything cryptoish with the cert object, more simply
PemWriter w = new PemWriter (/*suitable Writer as above */);
w.writeObject (new PemObject ("CERTIFICATE",raw));
w.close(); // ditto
For the standard-Java case you must do some of the work yourself:
// create or obtain a suitable Writer to file or whatever as w
w.write("-----BEGIN CERTIFICATE-----" + eol
+ Base64.getMimeEncoder().encodeToString(cert.getEncoded()) + eol
+ "-----END CERTIFICATE-----" + eol);
// w.flush() or w.close() if needed depending on the Writer
// or for a PrintStream (like System.out) optionally like
p.println("-----BEGIN CERTIFICATE-----");
p.write(Base64.getMimeEncoder().encode(cert.getEncoded());
p.println();
p.println("-----END CERTIFICATE-----");
// in principle eol should be appropriate for your output
// e.g. System.getProperty("line.separator") for a local file
// but possibly different for data sent someplace else;
// in practice PEM data usually works with either CRLF or LF
// on _all_ systems (and if not are usually easy to fix)
// _some_ systems even accept the base64 on one unbroken line
// as from Base64.getEncoder() rather than .getMimeEncoder()
// but I wouldn't suggest relying on that, it is nonstandard
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.