Search code examples
cdelphiopensslx509

Adding custom extension to PKCS#10 request using OpenSSL (programatically)


I would like to add custom extensions to a PKCS#10 request created via OpenSSL. The request generation and signing code works ok.

I am able to add known extensions via its nid, something like this (I am calling OpenSSL from Delphi):

as := 'critical,digitalSignature';
ext := X509V3_EXT_conf_nid(nil,nil,NID_key_usage,addr(as[1]));
sk_push(exts,ext);
X509_REQ_add_extensions(req,exts)

This works as expected. Now I have OID and data for the extension but I do not have a nid. As far as I found I can create a nid:

NID:= OBJ_create(PAnsiChar(aoid),PAnsiChar(ashortname),PAnsiChar(alongname));

But If I try to use this extension, I get Unknown Extension error. I found out that I need to tell OpenSSL how to handle my extension, for example by using a similar extension:

  X509V3_EXT_add_alias(nid,NID_netscape_comment);

But the question is, what if I do not have a similar extension to alias it to? For example I would like to add szOID_REQUEST_CLIENT_INFO (1.3.6.1.4.1.311.21.20) that is a sequence of integer and 3 UTF8Strings:

SEQUENCE 
{
clientId INTEGER,
MachineName UTF8STRING,
UserName UTF8STRING,
ProcessName UTF8STRING
} 

or szOID_ENROLLMENT_CSP_PROVIDER (1.3.6.1.4.1.311.13.2.2) which is basically a BMP string.

I have a code for creating DER bytes from ASN.1 so I could easily create the extension data as raw bytes for OpenSSL but I did not find a way how to create such a extension. Basically something like is described in man x509v3_config

1.2.3.4=DER:01:02:03:04

Solution

  • I finally managed to get it working. The main confusion is that I do not want to add a extension but an attribute. The extension can contain only OCTET STRING data. This can be achieved by specifying data as this:

    data := 'DER:310C160A3....';
    ext := X509V3_EXT_conf_nid(nil,nil,nid,addr(data[1]));
    

    In this case the X509V3_EXT_conf_nid does not complain about unknown extension (even without that aliasing) and creates extension that will be in form of:

      377:d=7  hl=2 l=  10 prim: OBJECT            :1.3.6.1.4.1.311.13.2.3
      389:d=7  hl=2 l=  15 prim: OCTET STRING      [HEX DUMP]:310C160A362E312E373630312E3230
    

    The extension will allways be a OCTET STRING as it should be and the DER encoded data are placed into it.

    However the attribute is on the same depth as the extensions and can contain any DER data. So

    data := loadfromhex('31091607312E322E33234');
    X509_REQ_add1_attr_by_nid(req,nid,ASN1_SEQUENCE,addr(data[1]),length(data));
    

    will produce the desired output:

      377:d=4  hl=2 l=  10 prim: OBJECT            :1.3.6.1.4.1.311.13.2.3
      389:d=4  hl=2 l=   9 cons: SET               
      391:d=5  hl=2 l=   7 prim: IA5STRING         :1.2.3.4