Generating a PKCS10 Certificate request with extra fields in java - java

I need to add extra fields in the CSR, like keyusage, regestrationID etc.I am using java IBM-sdk60. I've gone through x500 name API's and could not find any solution. Help on API's would be appreciated.
Thanks in advance

The standard way to include additional information in a CSR (PKCS#10) request is by adding Attributes. According to the PKCS#10 standard:
The intention of including a set of attributes is twofold: to provide
other information about a given entity , or a "challenge password" by
which the entity may later request certificate revocation; and to
provide attributes for inclusion in X.509 certificates. A
non-exhaustive list of attributes is given in PKCS #9
An attribute is an OID and a value whose meaning depends on the OID
Actually PKCS#9 defines 3 attributes:
Challenge password
Extension request
Extended-certificate attributes (this is deprecated)
The one you are looking for is Extension request :
The extensionRequest attribute type may be used to carry information
about certificate extensions the requester wishes to be included in a
certificate.
This code template (not tested) may give you some hints on how include this attribute
CertificateExtensions exts = /* build the extensions set you want to include */
/* Wrap the extensions set into a SET OF */
OutputStream out = new ByteArrayOutputStream();
exts.encode(out);
DerValue val = new DerValue(DerValue.tag_SetOf, out.toByteArray());
PKCSAttribute extReq = new PKCSAttribute(new ObjectIdentifier("1.2.840.113549.1.9.14"), val.toByteArray());
PKCSAttributes attrs = new PKCSAttributes(new PKCSAttribute[] { extReq });
CertificationRequestInfo cri = new CertificationRequestInfo(subject, key, attrs);
CertificationRequest csr = new CertificationRequest(cri);
Please note that unless the CA explicitly announces this PKCS#10 attribute is supported it will be ignored during the certificate generation.

Related

PDFBox Library to read Invisible PDFSignature from Signed PDF..Signer name is not shown

For a signed PDF document, with invisible signature, I am using PDFBox library to extract signer information, but it's coming as null. Same code works fine for visible signature. Can someone help on this if we need to make?
//Load PDF Document
PDDocument document = PDDocument.load(doc);
//Iterate each Signature
for (PDSignature pdSignature : document.getSignatureDictionaries()) {
if (pdSignature != null) {
HashMap values = new HashMap();
String subFilter = pdSignature.getSubFilter();
if (subFilter != null) {
LOG.debug("---------Siganature Details---------- ");
LOG.debug("Signer Name : " + pdSignature.getName());
values.put(SignerName, pdSignature.getName());
pdSignature.getName() returns the value of the Name entry of the signature dictionary. But this entry is optional:
Name text string (Optional) The name of the person or authority signing the document.
This value should be used only when it is not possible to extract the name from the signature.
Generally you'll have to analyze the signer certificate in the embedded signature container to get the common name of the signer.
As #Tilman pointed out in a comment, the pdfbox example ShowSignature shows quite a number of means to retrieve data from a CMS signature container.
On Your Comment
In a comment you write
Only the complete principal string can be extracted which contains the complete string using the below code "certFromSignedData.getSubjectX500Principal().toString()" [...] Any direct way of querying CN name alone?
Indeed you only get the complete subject distinguished name if you apply toString() to the X500Principal returned by certFromSignedData.getSubjectX500Principal(). But if you create a sun.security.x509.X500Name for it, you can easily retrieve the common name:
X500Principal principal = certFromSignedData.getSubjectX500Principal();
sun.security.x509.X500Name name = sun.security.x509.X500Name.asX500Name(principal);
System.out.printf("Whole DN: %s\n", name);
System.out.printf("CN: %s\n", name.getCommonName());
If you don't want to use sun.security.x509 classes, you can similarly use BouncyCastle classes, starting from the matching BouncyCastle X509CertificateHolder:
org.bouncycastle.asn1.x500.X500Name name = certificateHolder.getSubject();
System.out.printf("Whole DN: %s\n", name);
RDN[] cns = name.getRDNs(BCStyle.CN);
System.out.printf("CN: %s\n", cns.length > 0 ? cns[0].getFirst().getValue() : null);
however it's in different format for invisible and visible signature. For visible signature: SERIALNUMBER=xxxx, DNQ=xxx, EMAILADDRESS=xx, SURNAME=xx, GIVENNAME=xx, C=xx, CN=xx and for invisible signature "CN="xx" + EMAILADDRESS=xx, OU=xx, O="xx", L=xx, ST=xx, C=xx".
Which attributes are used in the subject DN and whether RDNs with multiple attribute/value pairs are used, depends on the signer certificate alone, it does not have anything to do with visible and invisible signature. If you have distinct specific patterns for invisible and visible signatures, then your test PDF pool is biased.

is there a way to add QualifyingPropertiesReference with xades4j?

I need to add two QualifyingPropertiesReference nodes with given URI values into Object within a XadES Signature.
I'm generating an xml Signature which requires to pass a certificate via URL instead of attaching it in KeyInfo element. For this, QualifyingPropertiesReference looks like a good fit, however I could not find a way or an example in wiki/tests that would add this element. Looking at the code, I found XmlQualifyingPropertiesReferenceType, but did not see it being used anywhere. My signing code:
XadesSigningProfile signingProfile =
new XadesBesSigningProfile(keyingDP)
.withBasicSignatureOptions(new BasicSignatureOptions().includeSigningCertificate(SigningCertificateMode.NONE));
XadesSigner signer = signingProfile.newSigner();
Document doc = createDocument(xmlMessage);
DataObjectDesc obj = new DataObjectReference("")
.withTransform(new EnvelopedSignatureTransform());
SignedDataObjects dataObjects = new SignedDataObjects().withSignedDataObject(obj);
signer.sign(dataObjects, doc.getFirstChild());
Basically, I want this kind of Signature structure:
<Signature>
....
<Object>
<QualifyingPropertiesReference URI="some_url"/>
<QualifyingPropertiesReference URI="some_url2"/>
<QualifyingProperties>
....
</Object>
</Signature>
If there's no way, would adding them to doc manually make Signature invalid? Are <Object> contents used for hashing?
xades4j doesn't support QualifyingPropertiesReference for two main reasons: 1) no real use cases for it; 2) XAdES Baseline profiles do not allow it section 6.1 of baseline profiles spec.
That said, I'm not sure your use-case is one for QualifyingPropertiesReference. This element is just a means of pointing to another XML resource where the qualifying properties are present. Maybe you misunderstood it. I don't think it has anything to do with certificates or how to obtain them.
It is ok that a signature doesn't include the certificates needed for validation. In this case the verifier is expected to know how to obtain them. Another option is to add "application-specific" data to the signature, where you pass the URL.

How to enable LTV for a timestamp signature and set the pdf change not allowed?

I am signing a pdf with digital certificate using iText. Now I can sign, and add LTV, but CertificateLevel can just be:
signatureAppearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS);
I just want to set PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED. The final result should look like this:
sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
MakeSignature.signDetached(signatureAppearance, privateKey, "SHA-512", chain, null, ocspClient, tsaClient, 0, MakeSignature.CryptoStandard.CADES);
If i use the above code to sign, then using AdobeLtvEnabling.java to add LTV will prompt the signature to be invalid when using ACROBAT check, because the file is modifying the unmodifiable PDF file when adding LTV. Thus, what can i do to approach the final effect.
To get a result like in your snapshot, i.e. both "No changes are allowed" and "Signature is LTV enabled" without any later signature or document timestamp, you have to
either already include all LTV material the Adobe validator requires into your original signed revision
or use a signing mode which allows you to append LTV material in spite of no changes being allowed.
Unfortunately the latter variant seems not yet to be properly supported by Adobe Acrobat Reader.
For details see the following sections.
Include all LTV material into the original signed revision
First of all, this is not always possible. If you want to have the LTV material in the original signed revision, it must be part of the signed data, so you have to collect it before signing. In many setups using remote signing services, though, you don't know which signing certificate exactly will be used before actually requesting the signature.
If it is possible, though, i.e. if you know the signing certificate in advance, you can use the class AdobeLtvEnabling from this stack overflow answer to include the information like this:
PdfStamper stamper = PdfStamper.createSignature(...);
AdobeLtvEnabling adobeLtvEnabling = new AdobeLtvEnabling(stamper);
OcspClient ocsp = new OcspClientBouncyCastle();
CrlClient crl = new CrlClientOnline();
adobeLtvEnabling.addLtvForChain(YOUR_SIGNER_CERTIFICATE, ocsp, crl, PdfName.A);
adobeLtvEnabling.outputDss();
[...preparing your signature...]
MakeSignature.signDetached(...);
(CreateSignatureComodo test testCreateLtvNoChangesAllowedCertification)
You might have to make the AdobeLtvEnabling methods addLtvForChain and outputDss public for this as AdobeLtvEnabling originally wsn't intended to be used like this.
The result:
Use a signing mode which allows appending LTV material but nothing else
Alternatively you can sign your PDF in a way that allows later addition of LTV material in spite of a "no changes allowed" certification.
To start with, it is necessary to make use of a mechanism first specified for PAdES signatures if you want to add LTV material to a PDF after applying the signature it is meant for. While this mechanism has meanwhile been included in ISO 32000-2, it is not available in a plain ISO 32000-1 context. As your screenshot is of a Adobe Acrobat, though, that shouldn't be an issue for you.
This mechanism are the document security stores. Both the iText class LtvVerification and the class AdobeLtvEnabling from this stack overflow answer fill such stores in a PDF.
Is it allowed to add these document security stores in spite of a "no changes allowed" certification? — It depends...
If your PDF is a PDF-2.0: yes. ISO 32000-2 characterizes the changes allowed or disallowed by some certification like this:
Changes to a PDF that are incremental updates which include only the data necessary to add DSS’s 12.8.4.3, "Document Security Store (DSS)" and/or document timestamps 12.8.5, "Document timestamp (DTS) dictionary" to the document shall not be considered as changes to the document as defined in the choices below.
(ISO 32000-2, Table 257 — Entries in the DocMDP transform parameters dictionary)
If your PDF is a PDF-1.x with the PAdES extensions enabled: yes. ETSI EN 319 142-1 requires
DocMDP restrictions (see ISO 32000-1 1, clause 12.8.2.2) shall not apply to incremental updates to a PDF document
containing a DSS dictionary and associated VRI, Certs, CRLs and OCSPs.
...
When evaluating the DocMDP restrictions (see ISO 32000-1 1, clause 12.8.2.2) the presence of a Document
Time-stamp dictionary item shall be ignored.
(ETSI EN 319 142-1 V1.1.1, section 5.4 Validation data and archive validation data attributes)
If your PDF is a plain PDF-1.x, though: no!
If you want to use this option and add LTV information after signing, therefore, make sure your originally certified PDF is a PDF-2 or has at least the PAdES extensions enabled.
While iText 5 does not support PDF-2, creating a PAdES style signature with it adds the PAdES extensions.
Thus, if you certify PAdES-style, you should be able to LTV-enable the signature even if the certification is "no changes allowed".
Support by Adobe Acrobat Reader DC 2019.008.20080
Having done some tests extending a no-changes allowed certified PDF with only LTV information, the PDF being either marked as PDF-1.7 with the appropriate ETSI and Adobe extensions or as PDF-2.0, it appears that Adobe Acrobat supports neither ETSI EN 319 142-1 nor ISO 32000-2 fully yet: In all tests it considered the certification as broken, cf. CreateSignatureComodo test testCreateNoChangesAllowedCertificationAndLtv.
For the time being, therefore, to get a document with LTV enabled no-changes-allowed certification and to have Adobe Acrobat recognize this, one only has the first option above, i.e. including all LTV material into the original signed revision.
A work-around might be to create the certification with form-filling-allowed, then adding LTV information, and then signing with another (approval) signature which changes the document to no-changes-allowed via its field lock dictionary and its FieldMDP transform, cf. CreateSignatureComodo test testCreateCertificationAndLtvAndNoChangesAllowed. As the incremental update of that signature can be removed by a knowledgeable person, though, this is far from perfect.
The result for the work-around:
I'm using itextsharp and I guess the following will be useful for your Java code too.
If you call MakeSignature.SignDetached with CrlClient and OcspClient (instead of passing null as parameter), you'll get a LTV-enabled signature after the first step. Then you needn't do the second step to add a document timestamp after.
var stamper = PdfStamper.CreateSignature(reader, stream, '\0', null, true);
var appearance = stamper.SignatureAppearance;
appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
...
var privateKey = ...
var chain = ...
var crlClient = new CrlClientOnline(chain);
var ocspClient = new OcspClientBouncyCastle();
var tsaClient = new TSAClientBouncyCastle("http://....");
MakeSignature.SignDetached(appearance, privateKey, chain,
new[] { crlClient },
ocspClient,
tsaClient,
0,
CryptoStandard.CMS);
stamper.Close();
Hope this works for you.

View details of a certificate in Android

How to display details of the subject in a certificate (DER format ie .cer file) in java ? eg: email, country, Name or seperate OIDs etc.
Reading a certificate could be done from the above code. Will work in Android as well. Thank you GreyBeardedGeek. But to more elaborate on it (As curious requested), if you display the subject details by using methods getSubjectDN() or cert.getSubjectX500Principal().getname() it will display the whole details. Some may be encoded. I believe it ASN1.(not sure). What I need is to extract only the information I need. For an example please refer the output of the code for a sample certificate I had created. using method - cert.getSubjectX500Principal().getname() Subject Name 2.5.4.5=#130d4e2d61626c652f49542f303130,2.5.4.72=#1308456e67696e656572,2.5.4.41=#13104e7577616e20446520416c6d65696461,1.2.840.113549.1.9.1=#16106e7577616e406e2d61626c652e62697a,OU=Information Technology,O=N-able Pvt Ltd\ ,ST=Western,C=LK
2.5.4.5 is an OID (Object Identifier) which is encoded.
Using method - getSubjectDN()
OID.2.5.4.5=N-able/IT/010, OID.2.5.4.72=Engineer, OID.2.5.4.41=Nuwan De Almeida, OID.1.2.840.113549.1.9.1=#16106E7577616E406E2D61626C652E62697A, OU=Information Technology, O="N-able Pvt Ltd ", ST=Western, C=LK
Here also some information is encoded eg: email address.
So coming back to my question , how can we extract information(not encoded) separately based on the OID. Further if you install the certificate in windows OS you could view the subject information correctly.What I need is a code to get the OID value information passing the OID in java, to extract subject details separately.
Thank you again in advance.
Look into the Bouncy Castle ASN.1 parsing libraries and especially X500Name. It can parse a distinguished name (DN) into its parts (CN, O, etc.).
http://www.bouncycastle.org/docs/docs1.5on/index.html
The following code (no error handling included) will produce an instance of X509Certificate from the .cer file. You can then use that object's methods to inspect the properties of the certificate. The code is generic java, but should work in Android.
X509Certificate cert = null;
FileInputStream fis = null;
ByteArrayInputStream bais = null;
String source = "certificate.cer";
String certType = "X.509"
fis = new FileInputStream(source);
byte[] value = new byte[fis.available()];
fis.read(value);
bais = new ByteArrayInputStream(value);
java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance(certType);
cert = (X509Certificate)cf.generateCertificate(bais);

Validate valid certificate with attribute PSEUDONYM

At the moment I'm receiving messages which are signed with a certificate.
So far so good.
However the certificate contains an attribute PSEUDONYM.
Now the Java runtime doesn't accept it. I get an IO Exception. (When I remove the PSEUDONYM exception is gone )
Does anybody know you to validate these messages as i'm sure that attribute PSEUDONYM is allowed.
C=DE,O=InfoCompany,OU=SoftwareMe,CN=SIGNER,SERIALNUMBER=1,PSEUDONYM=SIGNER
Any ideas how to change the default java validation to allow the PSEUDONYM tag?
Using constructor X500Principal(String name, Map<String,String> keywordMap) allows you to specify custom RDNs in keywordMap. The map's key is a RDN name and the value is a string representation of OID. See Java documentation for details.

Categories