]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Merge branch 'svn-branch-2.1' into merge
authorDavid Sommerseth <dazo@users.sourceforge.net>
Tue, 26 Apr 2011 21:04:18 +0000 (23:04 +0200)
committerDavid Sommerseth <dazo@users.sourceforge.net>
Tue, 26 Apr 2011 21:04:18 +0000 (23:04 +0200)
Pulling in changes from James' 2.1/openvpn branch in SVN.

Conflicts:
buffer.c
init.c
manage.h
multi.c
openvpn.8
options.c
ssl.c
version.m4
win/sign.py

Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
27 files changed:
1  2 
Makefile.am
buffer.c
buffer.h
common.h
configure.ac
error.c
forward.c
init.c
manage.c
misc.c
misc.h
multi.c
openvpn.8
openvpn.h
options.c
options.h
proto.h
ps.c
push.c
route.c
service-win32/openvpnserv.c
socket.c
ssl.c
ssl.h
syshead.h
tun.c
win/sign.py

diff --cc Makefile.am
Simple merge
diff --cc buffer.c
index 51cf7c1dfefb5ab94d2dea75eb3168e2819f6f6a,5499d99f2b49b2f3342978d5ba4e0eb56e7ed0e7..cff261667e42d77884de22e59f6bb6c94223c51c
+++ b/buffer.c
@@@ -234,15 -218,13 +234,17 @@@ buf_puts(struct buffer *buf, const cha
  /*
   * This is necessary due to certain buggy implementations of snprintf,
   * that don't guarantee null termination for size > 0.
 + *
+  * Return false on overflow.
++ *
 + * This function is duplicated into service-win32/openvpnserv.c
 + * Any modifications here should be done to the other place as well.
   */
  
int openvpn_snprintf(char *str, size_t size, const char *format, ...)
bool openvpn_snprintf(char *str, size_t size, const char *format, ...)
  {
    va_list arglist;
-   int ret = 0;
+   int len = -1;
    if (size > 0)
      {
        va_start (arglist, format);
diff --cc buffer.h
Simple merge
diff --cc common.h
Simple merge
diff --cc configure.ac
Simple merge
diff --cc error.c
index 9754464f8aef365800459b0e1d259c09556b9200,9cf4547e5e1f702373b0f5433e7d39bd0cdc19fd..2310f96a23441f9d24fbfdc4d1ba280ef9edeb3f
+++ b/error.c
@@@ -340,8 -353,10 +340,8 @@@ void x_msg (const unsigned int flags, c
      }
  
    if (flags & M_FATAL)
-     msg (M_INFO, "Exiting");
+     msg (M_INFO, "Exiting due to fatal error");
  
 -  mutex_unlock_static (L_MSG);
 -  
    if (flags & M_FATAL)
      openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
  
diff --cc forward.c
Simple merge
diff --cc init.c
index 6a9f1b71b873a7e9d46d5752dc71ebeca7585632,e5ca358edf6b8f83fd62e8d9679cf6907cae03f1..4a16fba44776037b269e78089cb2fea15526549f
--- 1/init.c
--- 2/init.c
+++ b/init.c
@@@ -1222,8 -1192,15 +1238,15 @@@ do_route (const struct options *options
          const struct plugin_list *plugins,
          struct env_set *es)
  {
 -  if (!options->route_noexec && route_list)
 +  if (!options->route_noexec && ( route_list || route_ipv6_list ) )
-     add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es);
+     {
 -      add_routes (route_list, tt, ROUTE_OPTION_FLAGS (options), es);
++      add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es);
+       setenv_int (es, "redirect_gateway", route_list->did_redirect_default_gateway);
+     }
+ #ifdef ENABLE_MANAGEMENT
+   if (management)
+     management_up_down (management, "UP", es);
+ #endif
  
    if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP))
      {
@@@ -2091,9 -2054,9 +2122,10 @@@ do_init_crypto_tls (struct context *c, 
  #endif
  
    to.verify_command = options->tls_verify;
 +  to.verify_export_cert = options->tls_export_cert;
    to.verify_x509name = options->tls_remote;
    to.crl_file = options->crl_file;
+   to.ssl_flags = options->ssl_flags;
    to.ns_cert_type = options->ns_cert_type;
    memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku));
    to.remote_cert_eku = options->remote_cert_eku;
diff --cc manage.c
Simple merge
diff --cc misc.c
Simple merge
diff --cc misc.h
Simple merge
diff --cc multi.c
index 12fb5cbb7e922d83fe4f1896556a76005d951a71,4ab1e723aa63d72d5d9e0cd8f03181d18ed6b1d4..15bea2268d21b504f0c63b03f0d9871b69331a63
+++ b/multi.c
@@@ -1237,17 -1200,9 +1237,20 @@@ multi_select_virtual_addr (struct multi
        mi->context.c2.push_ifconfig_defined = true;
        mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
        mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask;
+ #ifdef ENABLE_CLIENT_NAT
+       mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias;
+ #endif
 +
 +      /* the current implementation does not allow "static IPv4, pool IPv6",
 +       * (see below) so issue a warning if that happens - don't break the
 +       * session, though, as we don't even know if this client WANTS IPv6
 +       */
 +      if ( mi->context.c1.tuntap->ipv6 &&
 +         mi->context.options.ifconfig_ipv6_pool_defined &&
 +         ! mi->context.options.push_ifconfig_ipv6_defined )
 +      {
 +        msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work.  Use --ifconfig-ipv6-push for IPv6 then." );
 +      }
      }
    else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */
      {
diff --cc openvpn.8
index 95d060d9d714671e4f45d48b32af7fbdfe5f4f4c,85889de6a430980c60b371d77aba3c1378a7015f..5cbf4c57e82e4e06969714218c902ebdee5e448b
+++ b/openvpn.8
@@@ -1074,16 -1058,41 +1074,41 @@@ however note that this option still all
  to set the TCP/IP properties of the client's TUN/TAP interface.
  .\"*********************************************************
  .TP
 -.B --allow-pull-fqdn
 +.B \-\-allow-pull-fqdn
  Allow client to pull DNS names from server (rather than being limited
  to IP address) for
 -.B --ifconfig,
 -.B --route,
 +.B \-\-ifconfig,
 +.B \-\-route,
  and
 -.B --route-gateway.
 +.B \-\-route-gateway.
  .\"*********************************************************
  .TP
 -.B --client-nat snat|dnat network netmask alias
++.B \-\-client-nat snat|dnat network netmask alias
+ This pushable client option sets up a stateless one-to-one NAT
+ rule on packet addresses (not ports), and is useful in cases
+ where routes or ifconfig settings pushed to the client would
+ create an IP numbering conflict.
+ .B network/netmask
+ (for example 192.168.0.0/255.255.0.0)
+ defines the local view of a resource from the client perspective, while
+ .B alias/netmask
+ (for example 10.64.0.0/255.255.0.0)
+ defines the remote view from the server perspective.
+ Use
+ .B snat
+ (source NAT) for resources owned by the client and
+ .B dnat
+ (destination NAT) for remote resources.
+ Set
 -.B --verb 6
++.B \-\-verb 6
+ for debugging info showing the transformation of src/dest
+ addresses in packets.
+ .\"*********************************************************
+ .TP
 -.B --redirect-gateway flags...
 +.B \-\-redirect-gateway flags...
  (Experimental) Automatically execute routing commands to cause all outgoing IP traffic
  to be redirected over the VPN.
  
@@@ -2406,7 -2392,12 +2431,12 @@@ lines of log file history for usag
  by the management channel.
  .\"*********************************************************
  .TP
 -.B --management-up-down
++.B \-\-management-up-down
+ Report tunnel up/down events to management interface.
+ .B 
+ .\"*********************************************************
+ .TP
 -.B --management-client-auth
 +.B \-\-management-client-auth
  Gives management interface client the responsibility
  to authenticate clients after their client certificate
  has been verified.  See management-notes.txt in OpenVPN
@@@ -2740,9 -2731,9 +2770,9 @@@ This option is deprecated, and should b
  which is functionally equivalent.
  .\"*********************************************************
  .TP
- .B \-\-ifconfig-push local remote-netmask
 -.B --ifconfig-push local remote-netmask [alias]
++.B \-\-ifconfig-push local remote-netmask [alias]
  Push virtual IP endpoints for client tunnel,
 -overriding the --ifconfig-pool dynamic allocation.
 +overriding the \-\-ifconfig-pool dynamic allocation.
  
  The parameters
  .B local
@@@ -3259,7 -3240,7 +3298,7 @@@ disable the remapping feature.  Don't u
  know what you are doing!
  .\"*********************************************************
  .TP
- .B \-\-port-share host port
 -.B --port-share host port [dir]
++.B \-\-port-share host port [dir]
  When run in TCP server mode, share the OpenVPN port with
  another application, such as an HTTPS server.  If OpenVPN
  senses a connection to its port which is using a non-OpenVPN
@@@ -3902,7 -3887,23 +3951,23 @@@ that for certificate authority function
  ).
  .\"*********************************************************
  .TP
 -.B --extra-certs file
++.B \-\-extra-certs file
+ Specify a
+ .B file
+ containing one or more PEM certs (concatenated together)
+ that complete the
+ local certificate chain.
+ This option is useful for "split" CAs, where the CA for server
+ certs is different than the CA for client certs.  Putting certs
+ in this file allows them to be used to complete the local
+ certificate chain without trusting them to verify the peer-submitted
+ certificate, as would be the case if the certs were placed in the
+ .B ca
+ file.
+ .\"*********************************************************
+ .TP
 -.B --key file
 +.B \-\-key file
  Local peer's private key in .pem format.  Use the private key which was generated
  when you built your peer's certificate (see
  .B -cert file
@@@ -3913,12 -3914,23 +3978,23 @@@ above)
  Specify a PKCS #12 file containing local private key,
  local certificate, and root CA certificate.
  This option can be used instead of
 -.B --ca, --cert,
 +.B \-\-ca, \-\-cert,
  and
 -.B --key.
 +.B \-\-key.
  .\"*********************************************************
  .TP
 -.B --verify-hash hash
++.B \-\-verify-hash hash
+ Specify SHA1 fingerprint for level-1 cert.  The level-1 cert is the
+ CA (or intermediate cert) that signs the leaf certificate, and is
+ one removed from the leaf certificate in the direction of the root.
+ When accepting a connection from a peer, the level-1 cert
+ fingerprint must match
+ .B hash
+ or certificate verification will fail.  Hash is specified
+ as XX:XX:...  For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16
+ .\"*********************************************************
+ .TP
 -.B --pkcs11-cert-private [0|1]...
 +.B \-\-pkcs11-cert-private [0|1]...
  Set if access to certificate object should be performed after login.
  Every provider has its own setting.
  .\"*********************************************************
@@@ -4343,17 -4343,17 +4419,17 @@@ in the OpenVPN distribution
  
  See the "Environmental Variables" section below for
  additional parameters passed as environmental variables.
 -
 -Note that
 -.B cmd
 -can be a shell command with multiple arguments, in which
 -case all OpenVPN-generated arguments will be appended
 -to
 -.B cmd
 -to build a command line which will be passed to the script.
  .\"*********************************************************
  .TP
 -.B --tls-remote name
 +.B \-\-tls-export-cert directory
 +Store the certificates the clients uses upon connection to this
- directory. This will be done before --tls-verify is called.  The
++directory. This will be done before \-\-tls-verify is called.  The
 +certificates will use a temporary name and will be deleted when
 +the tls-verify script returns.  The file name used for the certificate
 +is available via the peer_cert environment variable.
 +.\"*********************************************************
 +.TP
 +.B \-\-tls-remote name
  Accept connections only from a host with X509 name
  or common name equal to
  .B name.
@@@ -4387,7 -4387,19 +4463,19 @@@ works in 
  environment too.
  .\"*********************************************************
  .TP
 -.B --x509-track attribute
++.B \-\-x509-track attribute
+ Save peer X509
+ .B attribute
+ value in environment for use by plugins and management interface.
+ Prepend a '+' to
+ .B attribute
+ to save values from full cert chain.  Values will be encoded
+ as X509_<depth>_<attribute>=<value>.  Multiple
 -.B --x509-track
++.B \-\-x509-track
+ options can be defined to track multiple attributes.
+ .\"*********************************************************
+ .TP
 -.B --ns-cert-type client|server
 +.B \-\-ns-cert-type client|server
  Require that peer certificate was signed with an explicit
  .B nsCertType
  designation of "client" or "server".
@@@ -4467,12 -4479,12 +4555,12 @@@ a man-in-the-middle attack where an aut
  attempts to connect to another client by impersonating the server.
  The attack is easily prevented by having clients verify
  the server certificate using any one of
 -.B --remote-cert-tls, --tls-remote,
 +.B \-\-remote-cert-tls, \-\-tls-remote,
  or
 -.B --tls-verify.
 +.B \-\-tls-verify.
  .\"*********************************************************
  .TP
- .B \-\-crl-verify crl
 -.B --crl-verify crl ['dir']
++.B \-\-crl-verify crl ['dir']
  Check peer certificate against the file
  .B crl
  in PEM format.
diff --cc openvpn.h
index e5e6e58d1415025a12344e37299242b5793eeb64,0ee439cad21b0ff57e609b3b31c39a84c4851b64..33661dff2b1f2f7eb0447d9c58def8f9586ecd77
+++ b/openvpn.h
@@@ -417,14 -414,13 +417,18 @@@ struct context_
    /* --ifconfig endpoints to be pushed to client */
    bool push_reply_deferred;
    bool push_ifconfig_defined;
+   bool sent_push_reply;
    in_addr_t push_ifconfig_local;
    in_addr_t push_ifconfig_remote_netmask;
+ #ifdef ENABLE_CLIENT_NAT
+   in_addr_t push_ifconfig_local_alias;
+ #endif
  
 +  bool            push_ifconfig_ipv6_defined;
 +  struct in6_addr push_ifconfig_ipv6_local;
 +  int             push_ifconfig_ipv6_netbits;
 +  struct in6_addr push_ifconfig_ipv6_remote;
 +
    /* client authentication state, CAS_SUCCEEDED must be 0 */
  # define CAS_SUCCEEDED 0
  # define CAS_PENDING   1
diff --cc options.c
index 8d1645d7755e19154f836f0d0c6c61d0fb35dbde,df7546ce65644b07cd0a8aa4865888e4e984ac73..f643acc01cbf514db0f71875426a1f4a5d0f2f18
+++ b/options.c
@@@ -530,10 -511,7 +536,11 @@@ static const char usage_message[] 
    "--key file      : Local private key in .pem format.\n"
    "--pkcs12 file   : PKCS#12 file containing local private key, local certificate\n"
    "                  and optionally the root CA certificate.\n"
 +#ifdef ENABLE_X509ALTUSERNAME
 +  "--x509-username-field : Field used in x509 certificat to be username.\n"
 +  "                        Default is CN.\n"
 +#endif
+   "--verify-hash   : Specify SHA1 fingerprint for level-1 cert.\n"
  #ifdef WIN32
    "--cryptoapicert select-string : Load the certificate and private key from the\n"
    "                  Windows Certificate System Store.\n"
@@@ -1235,13 -1140,15 +1280,22 @@@ rol_check_alloc (struct options *option
      options->routes = new_route_option_list (options->max_routes, &options->gc);
  }
  
 +void
 +rol6_check_alloc (struct options *options)
 +{
 +  if (!options->routes_ipv6)
 +    options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc);
 +}
 +
+ #ifdef ENABLE_CLIENT_NAT
+ static void
+ cnol_check_alloc (struct options *options)
+ {
+   if (!options->client_nat)
+     options->client_nat = new_client_nat_list (&options->gc);
+ }
+ #endif
  #ifdef ENABLE_DEBUG
  static void
  show_connection_entry (const struct connection_entry *o)
diff --cc options.h
Simple merge
diff --cc proto.h
Simple merge
diff --cc ps.c
Simple merge
diff --cc push.c
index 1fd8bea39ac0da69d69c9573086d54505378e945,5b870ce7ce3055584a0ff38c2b507f4f34e81c4a..a8ce3567f3fbfbe3241b483ebd2a8b312310b7c9
--- 1/push.c
--- 2/push.c
+++ b/push.c
@@@ -185,29 -231,10 +231,29 @@@ send_push_reply (struct context *c
    struct push_entry *e = c->options.push_list.head;
    bool multi_push = false;
    static char cmd[] = "PUSH_REPLY";
-   const int extra = 64; /* extra space for possible trailing ifconfig and push-continuation */
+   const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */
    const int safe_cap = BCAP (&buf) - extra;
 +  bool push_sent = false;
  
 -  buf_printf (&buf, cmd);
 +  msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap );
 +
 +  buf_printf (&buf, "%s", cmd);
 +
 +  if ( c->c2.push_ifconfig_ipv6_defined )
 +    {
 +      /* IPv6 is put into buffer first, could be lengthy */
 +      /* TODO: push "/netbits" as well, to allow non-/64 subnet sizes
 +       *       (needs changes in options.c, options.h, and other places)
 +       */
 +      buf_printf( &buf, ",ifconfig-ipv6 %s %s",
 +                  print_in6_addr( c->c2.push_ifconfig_ipv6_local, 0, &gc),
 +                  print_in6_addr( c->c2.push_ifconfig_ipv6_remote, 0, &gc) );
 +      if (BLEN (&buf) >= safe_cap)
 +      {
 +        msg (M_WARN, "--push ifconfig-ipv6 option is too long");
 +        goto fail;
 +      }
 +    }
  
    while (e)
      {
diff --cc route.c
Simple merge
index 5b0eb6e559edbe11659e98372f75ab9303e463c7,6c9ff1ec45c98f856ace996cb93890db1f43af36..099306405e73fac8dd083cf5433db782c5416bd4
@@@ -123,28 -133,6 +123,28 @@@ static HANDLE exit_event = NULL
        } \
    }
  
-   int ret = 0;
 +/*
 + * This is necessary due to certain buggy implementations of snprintf,
 + * that don't guarantee null termination for size > 0.
 + * (copied from ../buffer.c, line 217)
 + * (git: 100644 blob e2f8caab0a5b2a870092c6cd508a1a50c21c3ba3 buffer.c)
 + */
 +
 +int openvpn_snprintf(char *str, size_t size, const char *format, ...)
 +{
 +  va_list arglist;
-       ret = vsnprintf (str, size, format, arglist);
++  int len = -1;
 +  if (size > 0)
 +    {
 +      va_start (arglist, format);
-   return ret;
++      len = vsnprintf (str, size, format, arglist);
 +      va_end (arglist);
 +      str[size - 1] = 0;
 +    }
++  return (len >= 0 && len < size);
 +}
 +
 +
  bool
  init_security_attributes_allow_all (struct security_attributes *obj)
  {
diff --cc socket.c
Simple merge
diff --cc ssl.c
index bd7ac949a36f0940b033b6893aa9fa05efd7379b,df237ccf697bb1172428500b2fffcfba671e81e0..a2b5b189e7e87a208398cae819c5fdc49fc4e0be
--- 1/ssl.c
--- 2/ssl.c
+++ b/ssl.c
@@@ -521,58 -530,96 +533,148 @@@ extract_x509_field_ssl (X509_NAME *x509
    }
  }
  
 +#ifdef ENABLE_X509ALTUSERNAME
 +static
 +bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
 +{
 +  bool retval = false;
 +  X509_EXTENSION *pExt;
 +  char *buf = 0;
 +  int length = 0;
 +  GENERAL_NAMES *extensions;
 +  int nid = OBJ_txt2nid(fieldname);
 +
 +  extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL);
 +  if ( extensions )
 +    {
 +      int numalts;
 +      int i;
 +      /* get amount of alternatives,
 +       * RFC2459 claims there MUST be at least
 +       * one, but we don't depend on it...
 +       */
 +
 +      numalts = sk_GENERAL_NAME_num(extensions);
 +
 +      /* loop through all alternatives */
 +      for (i=0; i<numalts; i++)
 +        {
 +          /* get a handle to alternative name number i */
 +          const GENERAL_NAME *name = sk_GENERAL_NAME_value (extensions, i );
 +
 +          switch (name->type)
 +            {
 +              case GEN_EMAIL:
 +                ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5);
 +                if ( strlen (buf) != name->d.ia5->length )
 +                  {
 +                    msg (D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero");
 +                    OPENSSL_free (buf);
 +                  } else {
 +                    strncpynt(out, buf, size);
 +                    OPENSSL_free(buf);
 +                    retval = true;
 +                  }
 +                break;
 +              default:
 +                msg (D_TLS_ERRORS, "ASN1 ERROR: can not handle field type %i",
 +                     name->type);
 +                break;
 +            }
 +          }
 +        sk_GENERAL_NAME_free (extensions);
 +    }
 +  return retval;
+ #ifdef ENABLE_X509_TRACK
+ /*
+  * setenv_x509_track function -- save X509 fields to environment,
+  * using the naming convention:
+  *
+  *  X509_{cert_depth}_{name}={value}
+  *
+  * This function differs from setenv_x509 below in the following ways:
+  *
+  * (1) Only explicitly named attributes in xt are saved, per usage
+  *     of --x509-track program options.
+  * (2) Only the level 0 cert info is saved unless the XT_FULL_CHAIN
+  *     flag is set in xt->flags (corresponds with prepending a '+'
+  *     to the name when specified by --x509-track program option).
+  * (3) This function supports both X509 subject name fields as
+  *     well as X509 V3 extensions.
+  */
+ /* worker method for setenv_x509_track */
+ static void
+ do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth)
+ {
+   char *name_expand;
+   size_t name_expand_size;
+   string_mod (value, CC_ANY, CC_CRLF, '?');
+   msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth);
+   name_expand_size = 64 + strlen (name);
+   name_expand = (char *) malloc (name_expand_size);
+   check_malloc_return (name_expand);
+   openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name);
+   setenv_str (es, name_expand, value);
+   free (name_expand);
+ }
+ static void
+ setenv_x509_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509)
+ {
+   X509_NAME *x509_name = X509_get_subject_name (x509);
+   const char nullc = '\0';
+   int i;
+   while (xt)
+     {
+       if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
+       {
+         i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1);
+         if (i >= 0)
+           {
+             X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
+             if (ent)
+               {
+                 ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent);
+                 unsigned char *buf;
+                 buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
+                 if (ASN1_STRING_to_UTF8 (&buf, val) > 0)
+                   {
+                     do_setenv_x509(es, xt->name, (char *)buf, depth);
+                     OPENSSL_free (buf);
+                   }
+               }
+           }
+         else
+           {
+             i = X509_get_ext_by_NID(x509, xt->nid, -1);
+             if (i >= 0)
+               {
+                 X509_EXTENSION *ext = X509_get_ext(x509, i);
+                 if (ext)
+                   {
+                     BIO *bio = BIO_new(BIO_s_mem());
+                     if (bio)
+                       {
+                         if (X509V3_EXT_print(bio, ext, 0, 0))
+                           {
+                             if (BIO_write(bio, &nullc, 1) == 1)
+                               {
+                                 char *str;
+                                 BIO_get_mem_data(bio, &str);
+                                 do_setenv_x509(es, xt->name, str, depth);
+                               }
+                           }
+                         BIO_free(bio);
+                       }
+                   }
+               }
+           }
+       }
+       xt = xt->next;
+     }
  }
  #endif
  
@@@ -1108,53 -1069,73 +1211,73 @@@ verify_callback (int preverify_ok, X509
    /* check peer cert against CRL */
    if (opt->crl_file)
      {
-       X509_CRL *crl=NULL;
-       X509_REVOKED *revoked;
-       BIO *in=NULL;
-       int n,i,retval = 0;
+       if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
+       {
+         char fn[256];
+         int fd;
+         if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", opt->crl_file, OS_SPECIFIC_DIRSEP, serial))
+           {
+             msg (D_HANDSHAKE, "VERIFY CRL: filename overflow");
+             goto err;
+           }
+         fd = open (fn, O_RDONLY);
+         if (fd >= 0)
+           {
+             msg (D_HANDSHAKE, "VERIFY CRL: certificate serial number %s is revoked", serial);
+             close(fd);
+             goto err;
+           }
+       }
+       else
+       {
+         X509_CRL *crl=NULL;
+         X509_REVOKED *revoked;
+         BIO *in=NULL;
+         int n,i,retval = 0;
  
-       in=BIO_new(BIO_s_file());
+         in=BIO_new(BIO_s_file());
  
-       if (in == NULL) {
-       msg (M_ERR, "CRL: BIO err");
-       goto end;
-       }
-       if (BIO_read_filename(in, opt->crl_file) <= 0) {
-       msg (M_ERR, "CRL: cannot read: %s", opt->crl_file);
-       goto end;
-       }
-       crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
-       if (crl == NULL) {
-       msg (M_ERR, "CRL: cannot read CRL from file %s", opt->crl_file);
-       goto end;
-       }
+         if (in == NULL) {
+           msg (M_ERR, "CRL: BIO err");
+           goto end;
+         }
+         if (BIO_read_filename(in, opt->crl_file) <= 0) {
+           msg (M_ERR, "CRL: cannot read: %s", opt->crl_file);
+           goto end;
+         }
+         crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
+         if (crl == NULL) {
+           msg (M_ERR, "CRL: cannot read CRL from file %s", opt->crl_file);
+           goto end;
+         }
  
-       if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) {
-       msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", opt->crl_file, subject);
-       retval = 1;
-       goto end;
-       }
+         if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) {
+           msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", opt->crl_file, subject);
+           retval = 1;
+           goto end;
+         }
  
-       n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
 -        n = sk_num(X509_CRL_get_REVOKED(crl));
++          n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
  
-       for (i = 0; i < n; i++) {
-       revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
-       if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
-         msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
-         goto end;
-       }
-       }
 -        for (i = 0; i < n; i++) {
 -          revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i);
 -          if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
 -            msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
 -            goto end;
 -          }
 -        }
++          for (i = 0; i < n; i++) {
++            revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
++            if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
++              msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
++              goto end;
++            }
++          }
  
-       retval = 1;
-       msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
+         retval = 1;
+         msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
  
-     end:
+       end:
  
-       BIO_free(in);
-       if (crl)
-       X509_CRL_free (crl);
-       if (!retval)
-       goto err;
+         BIO_free(in);
+         if (crl)
+           X509_CRL_free (crl);
+         if (!retval)
+           goto err;
+       }
      }
  
    msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", ctx->error_depth, subject);
diff --cc ssl.h
Simple merge
diff --cc syshead.h
Simple merge
diff --cc tun.c
Simple merge
diff --cc win/sign.py
index 67d1cbc0dc1ad40035bcf68603ca42c811054c8c,93769514aea725a0766af7c3ea3ff93b3ef87284..a80bf98886e1f9b7db478da25508df2b253f5b86
@@@ -1,19 -1,23 +1,23 @@@
 -import sys\r
 -from wb import config, choose_arch, home_fn\r
 -\r
 -if 'SIGNTOOL' in config:\r
 -    sys.path.append(home_fn(config['SIGNTOOL']))\r
 -\r
 -def main(conf, arch, tap_dir):\r
 -    from signtool import SignTool\r
 -    st = SignTool(conf, tap_dir)\r
 -    for x64 in choose_arch(arch):\r
 -        st.sign_verify(x64=x64)\r
 -\r
 -# if we are run directly, and not loaded as a module\r
 -if __name__ == "__main__":\r
 -    if len(sys.argv) >= 2:\r
 -        if len(sys.argv) >= 3:\r
 -            tap_dir = home_fn(sys.argv[2])\r
 -        else:\r
 -            tap_dir = None\r
 -        main(config, sys.argv[1], tap_dir)\r
 -    else:\r
 -        print "usage: sign <x64|x86|all> [tap-dir]"\r
 -        sys.exit(2)\r
 +import sys
 +from wb import config, choose_arch, home_fn
 +
 +if 'SIGNTOOL' in config:
 +    sys.path.append(home_fn(config['SIGNTOOL']))
 +
- def main(conf, arch):
++def main(conf, arch, tap_dir):
 +    from signtool import SignTool
-     st = SignTool(conf)
++    st = SignTool(conf, tap_dir)
 +    for x64 in choose_arch(arch):
 +        st.sign_verify(x64=x64)
 +
 +# if we are run directly, and not loaded as a module
 +if __name__ == "__main__":
 +    if len(sys.argv) >= 2:
-         main(config, sys.argv[1])
++        if len(sys.argv) >= 3:
++            tap_dir = home_fn(sys.argv[2])
++        else:
++            tap_dir = None
++        main(config, sys.argv[1], tap_dir)
 +    else:
-         print "usage: sign <x64|x86|all>"
++        print "usage: sign <x64|x86|all> [tap-dir]"
 +        sys.exit(2)