1

How can I add something like a number to a X509 v3 Certificate?

X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(
                new X500Name("CN=Subject"),             
                serialNumber,
                startDate, expiryDate,
                new X500Name("CN=CA"),
                interPubInfo);

Think this works with .addExtension() but what comes after?

nolags
  • 633
  • 1
  • 11
  • 30
  • What do you mean? What kind of version? – Crypt32 May 12 '17 at 08:36
  • I want to add a number(int number = 123) for example .addExtension(number) – nolags May 12 '17 at 08:42
  • 2
    Extensions are not arbitrary data. They have structure, format and data. You can't pass just a number there. Extension consist of three main parts: object identifier (OID), whether the extension is critical and extension value. The format for common extensions is defined in ASN modules (PKIX modules are presented in RFC5280). For custom extensions custom format should be defined. – Crypt32 May 12 '17 at 08:58
  • So how can I add specific information to a x509 certificate? – nolags May 12 '17 at 09:06
  • 1
    It would be better if you would explain what you are trying to achieve. Seems like a XY problem case. – Crypt32 May 12 '17 at 09:11
  • I want to add an information/attribute to the certificate that I can proof later if this certificate has this attribute or not. For example I want to add the integer 123 and later i proof if this cert has exactly this number. – nolags May 12 '17 at 10:52
  • You can't just "add a number" anywhere. A digital certificate has a [well defined format](https://tools.ietf.org/html/rfc5280#section-4) and you can't just create new fields. You could add this number to **Subject** field, though (something like "CN=name,O=whatever,OU=123" - not the best solution, but enough for test purposes) –  May 12 '17 at 13:26
  • but there are extension fields. Can't I put in some Information there? – nolags May 16 '17 at 08:12

1 Answers1

4

As told in the comments, you can't just add arbitrary values anywhere in the certificate.

If you want to do it just for test or study purposes, you could use the Subject Alternative Name extension. This extension has some optional fields with a more "free" format:

OtherName ::= SEQUENCE {
    type-id    OBJECT IDENTIFIER,
    value      [0] EXPLICIT ANY DEFINED BY type-id }

So you could add an OtherName field with the values you want. The problem is the type-id field, because Object Identifiers can't be arbitrary values - they're actually standardized.

In a real-life scenario, you can't use the code below, because I'm using some arbitrary identifier (1.2.3.4.5.6.7.8.9) just to make it work. For a production certificate, you should use only pre-defined existent values.

That being said, I've made this code (in BouncyCastle 1.56) to add the extension with the value 123:

import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;

int number = 123;
ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier("1.2.3.4.5.6.7.8.9"); // some arbitrary non-existent OID number
DERSequence seq = new DERSequence(new ASN1Encodable[] { oid, new ASN1Integer(number) });

ArrayList<GeneralName> namesList = new ArrayList<>();
namesList.add(new GeneralName(GeneralName.otherName, seq));
GeneralNames subjectAltNames = GeneralNames.getInstance(new DERSequence((GeneralName[]) namesList.toArray(new GeneralName[] {})));

// certBuilder is a X509v3CertificateBuilder
certBuilder.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);

To read this extension from the certificate:

import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.x509.extension.X509ExtensionUtil;

X509Certificate cert = // a java.security.cert.X509Certificate
byte[] v = cert.getExtensionValue(Extension.subjectAlternativeName.getId());
GeneralNames gn = GeneralNames.getInstance(X509ExtensionUtil.fromExtensionValue(v));
GeneralName[] names = gn.getNames();
for (GeneralName name : names) {
    if (name.getTagNo() == GeneralName.otherName) {
        ASN1Sequence seq = ASN1Sequence.getInstance(name.getName());
        if ("1.2.3.4.5.6.7.8.9".equals(oid.getId())) { // OID is the arbitrary one I created
            ASN1Integer value = (ASN1Integer) seq.getObjectAt(1);
            int number = value.getValue().intValue();
            System.out.println(number); // number is 123
        }
    }
}
Community
  • 1
  • 1