Ticket #402: 0003-Make-extract_x509_extension-in-ssl_verify_openssl.c-.patch

File 0003-Make-extract_x509_extension-in-ssl_verify_openssl.c-.patch, 7.9 KB (added by Steffan Karger, 8 years ago)
  • src/openvpn/ssl_verify.c

    From 1cd060230653bd93067a0837384907200fa19c74 Mon Sep 17 00:00:00 2001
    From: Andris Kalnozols <andris@hpl.hp.com>
    Date: Sat, 28 Jun 2014 20:26:21 +0200
    Subject: [PATCH 3/3] Make extract_x509_extension() in ssl_verify_openssl.c
     more informative.
    
    I did enhance extract_x509_extension() in ssl_verify_openssl.c to be more
    informative but only when dealing with the client certificate. Getting
    access to the "cert_depth" variable required minor changes in the following
    files:
        ssl_verify.c
        ssl_verify_backend.h
        ssl_verify_polarssl.c
    
    Signed-off-by: Andris Kalnozols <andris@hpl.hp.com>
    ---
     src/openvpn/ssl_verify.c          |   2 +-
     src/openvpn/ssl_verify_backend.h  |   3 +-
     src/openvpn/ssl_verify_openssl.c  | 134 +++++++++++++++++++++++---------------
     src/openvpn/ssl_verify_polarssl.c |   2 +-
     4 files changed, 86 insertions(+), 55 deletions(-)
    
    diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c
    index c90c2c3..19df9fb 100644
    a b verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep 
    620620
    621621  /* extract the username (default is CN) */
    622622  if (SUCCESS != x509_get_username (common_name, TLS_USERNAME_LEN,
    623       opt->x509_username_field, cert))
     623      opt->x509_username_field, cert, cert_depth))
    624624    {
    625625      if (!cert_depth)
    626626        {
  • src/openvpn/ssl_verify_backend.h

    diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h
    index 6f118c9..14383ad 100644
    a b unsigned char *x509_get_sha1_hash (openvpn_x509_cert_t *cert, struct gc_arena *g 
    106106 * @param cn_len                Length of the cn buffer.
    107107 * @param x509_username_field   Name of the field to load from
    108108 * @param cert                  Certificate to retrieve the common name from.
     109 * @param cert_depth            Depth of the current certificate
    109110 *
    110111 * @return              \c FAILURE, \c or SUCCESS
    111112 */
    112113result_t x509_get_username (char *common_name, int cn_len,
    113     char * x509_username_field, openvpn_x509_cert_t *peer_cert);
     114    char * x509_username_field, openvpn_x509_cert_t *peer_cert, int cert_depth);
    114115
    115116/*
    116117 * Return the certificate's serial number in decimal string representation.
  • src/openvpn/ssl_verify_openssl.c

    diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c
    index 19982ae..e5a6904 100644
    a b cleanup: 
    9393}
    9494
    9595#ifdef ENABLE_X509ALTUSERNAME
    96 static
    97 bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
     96static result_t
     97extract_x509_extension(X509 *cert, int cert_depth, char *fieldname,
     98                       char *out, int size)
    9899{
    99   bool retval = false;
    100   X509_EXTENSION *pExt;
    101   char *buf = 0;
     100  result_t retval = FAILURE;
     101  int nid;
    102102  int length = 0;
    103   GENERAL_NAMES *extensions;
    104   int nid = OBJ_txt2nid(fieldname);
     103  char *buf  = 0;
     104  GENERAL_NAMES *extension;
    105105
    106   extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL);
    107   if ( extensions )
     106  nid = OBJ_txt2nid(fieldname);
     107  extension = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL);
     108  if (!extension && cert_depth == 0)
     109      /*
     110       * The cert depth is used to filter message logging to just the
     111       * client certificate; we're not concerned about the CA(s) here.
     112       */
     113      msg(D_TLS_ERRORS, "VERIFY ERROR: can not find extension %s",
     114          fieldname);
     115  else
    108116    {
    109117      int numalts;
    110118      int i;
    111       /* get amount of alternatives,
    112        * RFC2459 claims there MUST be at least
    113        * one, but we don't depend on it...
     119      STACK_OF(CONF_VALUE) *vals = sk_CONF_VALUE_new_null();
     120
     121      /* Get the number of alternatives, i.e., GeneralName fields.
     122       * RFC5280, Section 4.2.1.6 states there MUST be at least
     123       * one and that no GeneralName field may have an empty value.
     124       * We will not trust but verify instead.
    114125       */
    115126
    116       numalts = sk_GENERAL_NAME_num(extensions);
    117 
    118       /* loop through all alternatives */
    119       for (i=0; i<numalts; i++)
    120         {
    121           /* get a handle to alternative name number i */
    122           const GENERAL_NAME *name = sk_GENERAL_NAME_value (extensions, i );
    123 
    124           switch (name->type)
    125             {
    126               case GEN_EMAIL:
    127                 ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5);
    128                 if ( strlen (buf) != name->d.ia5->length )
    129                   {
    130                     msg (D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero");
    131                     OPENSSL_free (buf);
    132                   } else {
    133                     strncpynt(out, buf, size);
    134                     OPENSSL_free(buf);
    135                     retval = true;
    136                   }
    137                 break;
    138               default:
    139                 msg (D_TLS_ERRORS, "ASN1 ERROR: can not handle field type %i",
    140                      name->type);
    141                 break;
    142             }
    143           }
    144         sk_GENERAL_NAME_free (extensions);
     127      i2v_GENERAL_NAMES(NULL, extension, vals);
     128      numalts = sk_GENERAL_NAME_num(extension);
     129      if (cert_depth == 0)
     130        msg(M_INFO, "Found extension %s with %i alternative name(s)", fieldname,
     131            numalts);
     132
     133      /* loop through all of the alternatives */
     134      for (i = 0; i < numalts; i++)
     135        {
     136          /* Get a handle to alternative GeneralName number "i"
     137           * and to its associated OpenSSL configuration name.
     138           */
     139          const GENERAL_NAME *name = sk_GENERAL_NAME_value(extension, i);
     140          const CONF_VALUE *conf   = sk_CONF_VALUE_value(vals, i);
     141
     142          switch (name->type)
     143            {
     144              case GEN_EMAIL:
     145                ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5);
     146                if (strlen(buf) != name->d.ia5->length)
     147                   msg(D_TLS_ERRORS,
     148                       "ASN1 ERROR: field '%s' (%i of %i) has an embedded NUL",
     149                       conf->name, i, numalts);
     150                else
     151                if (name->d.ia5->length == 0)
     152                   msg(D_TLS_ERRORS,
     153                        "Field '%s' (%i of %i) has an empty value",
     154                        conf->name, i, numalts);
     155                else
     156                  {
     157                    strncpynt(out, buf, size);
     158                    if (cert_depth == 0)
     159                      if (retval == SUCCESS)
     160                        msg(M_INFO, "Updating common name to '%s'", out);
     161                      else
     162                        msg(M_INFO, "Setting common name to '%s'", out);
     163                    retval = SUCCESS;
     164                  }
     165                OPENSSL_free(buf);
     166                break;
     167
     168              default:
     169                if (cert_depth == 0)
     170                  msg(D_TLS_DEBUG, "Ignoring alternative type '%s'",
     171                      conf->name);
     172                break;
     173            }
     174        }
     175      sk_CONF_VALUE_free(vals);
    145176    }
     177  sk_GENERAL_NAME_free(extension);
    146178  return retval;
    147179}
    148180#endif /* ENABLE_X509ALTUSERNAME */
    extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, 
    203235
    204236result_t
    205237x509_get_username (char *common_name, int cn_len,
    206     char * x509_username_field, X509 *peer_cert)
     238    char * x509_username_field, X509 *peer_cert, int cert_depth)
    207239{
     240  result_t retval;
    208241#ifdef ENABLE_X509ALTUSERNAME
    209   if (strncmp("ext:",x509_username_field,4) == 0)
    210     {
    211       if (!extract_x509_extension (peer_cert, x509_username_field+4, common_name, cn_len))
    212         return FAILURE;
    213     } else
     242  if (strncmp("ext:", x509_username_field, 4) == 0)
     243    retval = extract_x509_extension(peer_cert, cert_depth,
     244               x509_username_field+4, common_name, cn_len);
     245  else
    214246#endif
    215   if (FAILURE == extract_x509_field_ssl (X509_get_subject_name (peer_cert),
    216       x509_username_field, common_name, cn_len))
    217       return FAILURE;
    218 
    219   return SUCCESS;
     247    retval = extract_x509_field_ssl(X509_get_subject_name(peer_cert),
     248               x509_username_field, common_name, cn_len);
     249  return retval;
    220250}
    221251
    222252char *
  • src/openvpn/ssl_verify_polarssl.c

    diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c
    index 8931f8a..25f1550 100644
    a b verify_callback (void *session_obj, x509_cert *cert, int cert_depth, 
    9191
    9292result_t
    9393x509_get_username (char *cn, int cn_len,
    94     char *x509_username_field, x509_cert *cert)
     94    char *x509_username_field, x509_cert *cert, int cert_depth)
    9595{
    9696  x509_name *name;
    9797