Hi all,

Does someone know why custom extensions of an X509 certificate request apparently get stripped when the PEM_write_X509_REQ function is used to dump the request to a file ?

The code (based on demos/x509/mkreq.c) that I use is attached.
To compile the code, simply do:
 gcc -g -Wall -lcrypto -o gcs-add-ext gcs-add-ext.c

To try the code, you can do:
cat basic-user.req | ./gcs-add-ext -r user:admin -V | openssl req -text

There, you will see that my extension gets added to the certificate request but is actually missing in the PEM encoded output produced by PEM_write_X509_REQ.

Thanks for any idea for a fix/workaround.

Best,
Jacques Thomas
/*
 * Filename: gcs-add-exts.c
 * Purpose: program to add extensions for gcs access control in a PEM encoded x509
 * certificate request
 *
 * Author: Jacques Thomas <[EMAIL PROTECTED]>
 * Credits: Markus Loch and the OpenSSL demo apps authors
 */

#include <stdio.h>
#include <unistd.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/asn1.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "gcs-exts.h"

#define false 0
#define true  1

int add_ext(STACK_OF(X509_REQUEST) *sk, int nid, char *value);

/* arguments retrieved from the command line */
char *infile = NULL;
char *outfile = NULL;
char *roles = NULL;
int verbose = false;

/* to use with sprintf for complicated error messages */
char errmsg[256];

void parse_opts(int argc, char *argv[]){
  char *optstring = "hi:o:r:V";
  char *usage = "[-h] [-V] [-i <input cert req>] [-o <output cert req>] [-r <role1[:role2 ...]]>";
  char *usage_long = "TODO: write detailed usage explanations";
  char c;

  while((c = getopt(argc, argv, optstring))){
    switch(c){
    case 'h':
      fprintf(stdout, "Usage:\n\t %s %s\n%s\n", argv[0], usage, usage_long);
      exit (0);
    case 'i':
      infile = optarg;
      break;
    case 'o':
      outfile = optarg;
      break;
    case 'r':
      roles = optarg;
      break;
    case 'V':
      verbose = true;
      break;
    case '?': /* unrecognized option */
      fprintf(stderr, "Usage:\n\t %s %s\n", argv[0], usage);
      exit (1);
    case -1: /* no more options */
      return;
    }
  }
  return; /* just to tranquilize the compiler ; we exit straight from the while loop */
}

int main (int argc, char *argv[])
{
  X509_REQ *req=NULL;
  FILE *infp, *outfp;
  STACK_OF(X509_EXTENSION) *exts = NULL;
  int nid;
  

  /* parse the options from the command line */
  parse_opts(argc, argv);


  OpenSSL_add_all_algorithms ();
  ERR_load_crypto_strings ();

  /* load the certificate request */
  if(verbose)
    fprintf (stderr,"Loading the certificate request now \n");
  if (infile == NULL)
    infp = stdin;
  else {
    if (!(infp = fopen (infile, "r")))
      perror ("Error accessing certificate file");
  }
  if (!(req = PEM_read_X509_REQ (infp, NULL, NULL, NULL)))
    perror ("Error reading certificate file" );
  fclose (infp);

  /* if needed, open the output file */
  if (outfile == NULL)
    outfp = stdout;
  else {
    if (!(outfp = fopen (outfile, "w"))){
      sprintf(errmsg, "Error opening output file %s", outfile);
      perror (errmsg);
    }
  }

  /* the default role is the user role */
  if (roles == NULL)
    roles = "user";

  /* print the certificate request before modification*/
  if(verbose){
    fprintf(stderr, "Certificate request before modification:\n");
    X509_REQ_print_fp(stderr,req);
  }

  /* initialize the extensions stack */
  exts = sk_X509_EXTENSION_new_null();

  /* now add the GCS role extension */
  nid = OBJ_create(GCS_ROLE_OID, "GCSRole", "GCS Role Attribute");
  X509V3_EXT_add_alias(nid, NID_netscape_comment);
  add_ext(exts, nid, roles);  
  /* add the extension to the request */
  X509_REQ_add_extensions(req, exts);

  /* cleanup */
  sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);

  /* print the certificate request after modification */
  if(verbose){
    fprintf(stderr, "\n\n\nCertificate request after modification:\n");
    X509_REQ_print_fp(stderr,req);
  }

  /* output the PEM encoded certifcate request to the proper output file */
  PEM_write_X509_REQ(outfp,req);
  return(0);
}


/* Add extension using V3 code: we can set the config file as NULL
 * because we wont reference any other sections.
 */

int add_ext(STACK_OF(X509_REQUEST) *sk, int nid, char *value)
{
  X509_EXTENSION *ex;
  ex = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
  if (!ex)
    return 0;
  sk_X509_EXTENSION_push(sk, ex);
  
  return 1;
}
	
-----BEGIN CERTIFICATE REQUEST-----
MIIBrTCCARYCAQAwbTELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0luZGlhbmExFzAV
BgNVBAcTDldlc3QgTGFmYXlldHRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRz
IFB0eSBMdGQxEDAOBgNVBAMTB0phY3F1ZXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBAMNArsxzS98UZ3OTNlLaBDEfbNBs5/sUp/8WDrk8+a+TBKyhGoD7OIYK
HI0Z8FGwGifvNP2VlxHZiDaiqM6j36FCS/SG8lD6JjJXiXVoCTVdOfO3sRFg+mIM
fJ3zDcOCFx1PFiR+0273C1OFzDBdWqGBUPwuSMtjIweBBLB/JesLAgMBAAGgADAN
BgkqhkiG9w0BAQQFAAOBgQAUyYEitN9DVYQETFqCmRkgm27CrFEcu1P6ayulRJ8f
Cs37HMhDHT/0PO1ggH9zLnT8wkQBC+ucMWC0ayEjaRHPjxmTumfBljvxF33VGuPD
Q+MIJEHOpl0TsUpreAoGF9CsA+/JJCbbWDI+7vJrrEqw6PvT2Z57q4Vh9dfwuYuu
bQ==
-----END CERTIFICATE REQUEST-----

Reply via email to