pax_global_header00006660000000000000000000000064126035710560014517gustar00rootroot0000000000000052 comment=3e91d3dbc5ded79d42a02edcce7b6a0d895ecdeb mod_nss-1.0.12/000077500000000000000000000000001260357105600132425ustar00rootroot00000000000000mod_nss-1.0.12/.gitignore000066400000000000000000000004671260357105600152410ustar00rootroot00000000000000configure config.h config.h.in Makefile Makefile.in .deps/ .libs/ *.la *.lo *.o version.m4 aclocal.m4 autom4te.cache/ config.guess config.log config.status config.sub depcomp install-sh ltmain.sh missing ylwrap libtool # Python compilation *.pyc py-compile # Generated files gencert nss.conf test/variable.py mod_nss-1.0.12/AUTHORS000066400000000000000000000003061260357105600143110ustar00rootroot00000000000000The following people have contributed to mod_nss, in alphabetical order: Rob Crittenden Wolter Eldering Kai Engert Oden Eriksson Matthew Harmsen Tomas Hoger Joshua Roys Stanislav Tokos Ulf Weltman mod_nss-1.0.12/COPYING000066400000000000000000000000001260357105600142630ustar00rootroot00000000000000mod_nss-1.0.12/ChangeLog000066400000000000000000000247641260357105600150310ustar00rootroot000000000000002015-10-02 Rob Crittenden * Integrate patch from Stanislav Tokos to set the SNI hostname on reverse proxy requests. * Cleanup a bunch of trailing whitespace spread across all the source files. * Become 1.0.12 2015-10-01 Rob Crittenden * Add compatibility for Apache 2.2 and older versions of NSS. Tested on RHEL 6.5. * Replace some PR_Free calls with more correct PORT_Free. * Initialize session_tickets as FALSE instead of UNSET. * Modernize the autotools configuration, generate config.h * Get the version from config.h to get the proper mod_nss version for reporting at runtime. It previously displayed the version of Apache where the mod_nss version should have gone. 2015-09-25 Rob Crittenden * Add support for SNI * Display hints if there are issues initializing NSS 2015-09-24 Rob Crittenden * Fix bad memory access and memory leak in CGI variables * Add optional support for some SHA384 ciphers * Add the SECURE_RENEG environment variable 2015-09-21 Rob Crittenden * Fix a bunch of issues related to OpenSSL cipher parsing 2015-08-27 Rob Crittenden * Fix a bunch of compiler warnings * Permanently disabled openssl ciphers could be enabled (CVE-2015-5244) 2015-07-28 Matthew Harmsen * Add 'v' to refererences of protocols (e.g. SSLv3) (#1066236) 2015-07-27 Rob Crittenden * Add RenegBufferSize option (#1214366) * Add support for TLS Session Tickets (RFC 5077) * Fix logical AND support in OpenSSL cipher compatibility (CVE-2015-3276) 2014-12-10 Rob Crittenden * Become 1.0.11 2014-11-12 Rob Crittenden * Add compatability for mod_ssl-style cipher definitions (#862938) * Add Camelia ciphers * Remove Fortezza ciphers * Add TLSv1.2-specific ciphers 2014-11-12 Rob Crittenden * Initialize ciphers to all disabled before renegotiation (#1165408) 2014-11-06 Rob Crittenden * Completely remove support for SSLv2 2014-10-28 Rob Crittenden * Add support for sqlite NSS databases (#1057650) 2014-10-22 Stanislav Tokos * Compare subject CN and VS hostname during server start up 2014-10-16 Rob Crittenden * Add support for enabling TLS v1.2 * Don't enable SSL 3 by default (CVE-2014-3566) * Improve protocol testing 2014-02-20 Rob Crittenden * Sync with Fedora builds which were basicaly the defacto upstream. * Add nss_pcache man page * Fix CVE-2013-4566 * Move nss_pcache to /usr/libexec * Fix argument handling in nss_pcache * Support httpd 2.4+ 2013-10-11 Tomas Hoger * Documentation formatting fixes 2013-10-11 Rob Crittenden * Only clear the SSL Session Cache when shutting the server down. 2013-10-11 Matthew Harmsen * Add support for TLS v1.1 2013-07-02 Matthew Harmsen * Add man page for nss_pcache, update man page for gencert 2011-10-09 Rob Crittenden * Fix static array overrun when generating arg list for nss_pcache 2011-06-14 Rob Crittenden * Always copy in client certificate and fix FakeBasicAuth * When NSSOptions +FakeBasicAuth is set for a directory, and a certificate is not provided with which the BasicAuth can be Faked, and the client provides an Authorization header, the FakeBasicAuth code in mod_nss may not properly reject an attempt to spoof. * No need to shut things down if NSS isn't initialized. 2011-03-02 Rob Crittenden * Add semaphore lock around retrieving token PINs to avoid overruns. 2011-02-03 Rob Crittenden * Add man page for gencert 2011-01-12 Rob Crittenden * Don't use memcpy as it may operate on overlapping memory (#669118) Patch ported from mod_ssl by Stephen Gallagher 2010-09-22 Rob Crittenden * Only call PK11_ListCerts once and pass it when configuring each virtual server. This saves considerable time when there are a lot of certificates and/or virtual servers. (#635324) * Change enforce so that we only check the validity of the certificate if enforcecerts is enabled (the default). Patch contributed by Wolter Eldering 2010-09-17 Rob Crittenden * Fix endless read loop in some situations when handling POST data (#620856) This was discovered in the dogtag TPS subsystem. I haven't been able to duplicate it outside of that but it is trivial inside. This seems to fix it and brings the code closer to what mod_ssl does here as well. 2010-05-14 Rob Crittenden * Ignore SIGHUP in nss_pcache (#591889). Contributed by Joshua Roys 2010-05-13 Rob Crittenden * Compare CN value of remote host with requested host in reverse proxy. * Add configuration option to disable this, defaulting to on. (#591224) Based on patch from Joshua Roys 2010-03-22 Rob Crittenden * Update list of errors we translate 2010-03-02 Rob Crittenden * Add controls for managing SSL renegotiation NSS is introducing some new controls in response to CVE-2009-3555, MITM attacks via session renegotiation. This patch adds some tuning so these options can be set at run time. Patch contributed by Kai Engert 2008-07-21 Rob Crittenden * mod_nss 1.0.8 2008-07-02 Rob Crittenden * Don't allow blank passwords if FIPS is enabled. This is not allowed by the NSS FIPS 140-2 security policy. 2008-05-16 Rob Crittenden * No need to link with softokn3 * Fix FIPS mode * There seem to be a problem in NSS_Shutdown() that makes subsequent logins appear to succeed but they actually are skipped causing keys and certs to not be available. * Also switch an error message to a warning related to FIPS ciphers. 2008-05-09 Rob Crittenden * NSS has been modified to not allow a fork after an NSS_Init() in the soft token. It apparently always did this for hardware tokens as it is part of the PKCS#11 spec. * This moves the initialization code into the child process init function. 2008-01-03 Rob Crittenden * See if the certificate has a version before trying to decode it into a CGI variable. 2007-10-18 Rob Crittenden * If mod_ssl isn't loaded then register the hooks to mod_proxy so we can do at least secure proxy in front of an unsecure host. 2007-06-07 Rob Crittenden * The error message was wrong if NSSPassPhraseHelper pointed to a non-existant file. * Don't require a password file AND NSSPassPhraseHelper. Only the helper is required. 2007-06-01 Rob Crittenden * mod_nss 1.0.7 * Stop processing tokens when a login fails so we can correctly report the failure. * Fix an off-by-one error in nss_pcache that prevented 1 character passwords (not a huge problem but a bug none-the-less). * Bring in some updates based on diffs from 2.0.59 to 2.2.4 * Do explicit TRUE/FALSE tests with sc->enabled to see if SSL is enabled. * Don't depend on the fact that TRUE == 1 * Remove some dead code * Minor update to the buffer code that buffers POST data during a renegotation * Optimize setting environment variables by using a switch statement. * Fix typo in cipher echde_rsa_null (transposed h and d). * The way I was using to detect the model being used was incorrect. Now use the # of threads available. Guaranteed to be 0 for prefork and > 0 for worker (threaded) 2006-10-27 Rob Crittenden * mod_nss 1.0.6 * If NSSEngine is off then simply don't initialize NSS at all. * Add support for setting a default OCSP responder. 2006-10-17 Rob Crittenden * mod_nss 1.0.5 * Fix for a minor problem introduced with 1.0.4. NSS_Shutdown() was being called during module unload even if SSL wasn't enabled causing an error to display in the log. 2006-10-11 Rob Crittenden * mod_nss 1.0.4 * Merged in some changes from mod_ssl: * new env variables SSL_{SERVER,CLIENT}_V_REMAIN that contains number of days until certificate expires * Attempt to buffer POST data in a SSL renegotiation. * And some changes specific to mod_nss: * Better way to distinguish Apache 2.0.x versus Apache 2.2.x. The old way broke when 2.0.56 was introduced. * Fix crash bug if the stored token password doesn't match the database password * Add new NSSPassPhraseDialog method, defer, where only the tokens that are found in the file pointed to by this directive are initialized. * Fix race condition in initializing the NSS session cache that could cause a core on startup. * Update nss.conf.in to contain LogLevel and its own log files * A missing initialization when built with ECC support that could cause the server to not start 2006-06-21 Rob Crittenden * mod_nss 1.0.3 * Final ECC support * Compiles on Solaris with the Forte Workshop compiler (tested with 6.2 and 11). * A number of compilation warnings were addressed * gencert now uses bash instead of ksh 2006-03-02 Rob Crittenden * Experimental Eliptical Curve Cryptopgraphy (ECC) added. Requires a version of NSS also build with ECC support. Available in the CVS tip. 2006-01-31 Rob Crittenden * mod_nss 1.0.2 * Add support for Apache 2.2 (contributed by Oden Eriksson) 2006-09-20 Rob Crittenden * mod_nss 1.0.0 * Support for SSLv2, SSLv3, TLSv1 * OCSP and CRLs * Client certificate authentication * Can run concurrently with mod_ssl mod_nss-1.0.12/INSTALL000066400000000000000000000366001260357105600143000ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. mod_nss-1.0.12/LICENSE000066400000000000000000000261351260357105600142560ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mod_nss-1.0.12/Makefile.am000066400000000000000000000074131260357105600153030ustar00rootroot00000000000000## This is the shared library to be built lib_LTLIBRARIES = libmodnss.la bin_PROGRAMS = nss_pcache test_cipher nss_pcache_SOURCES = nss_pcache.c test_cipher_SOURCES = test_cipher.c nss_engine_cipher.c test_cipher_CFLAGS = $(AM_CFLAGS) $(CFLAGS) $(EXTRA_CPPFLAGS) man8_MANS = \ gencert.8 \ nss_pcache.8 \ $(NULL) install-data-hook: @for i in $(man8_MANS) ; do gzip -f $(DESTDIR)$(man8dir)/$$i ; done ## Define the source file for the module libmodnss_la_SOURCES = mod_nss.c nss_engine_config.c nss_engine_init.c nss_engine_io.c nss_engine_kernel.c nss_engine_log.c nss_engine_pphrase.c nss_engine_vars.c nss_expr.c nss_expr_eval.c nss_expr_parse.y nss_expr_scan.l nss_util.c nss_engine_rand.c nss_engine_cipher.c libmodnss_la_LDFLAGS = -module -avoid-version ## Set the includes and libraries needed AM_CPPFLAGS = -I@apache_inc@ @nspr_inc@ @nss_inc@ @apr_inc@ LIBS = @nspr_lib@ @nss_lib@ -lssl3 -lsmime3 -lnss3 -lplc4 -lplds4 -lnspr4 EXTRA_CPPFLAGS=@extra_cppflags@ install-libLTLIBRARIES: libmodnss.la @APXS@ -i -a -n nss libmodnss.la if [ -d @apache_conf@/../conf.d ]; then \ if [ ! -f @apache_conf@/../conf.d/nss.conf ]; then \ $(INSTALL_DATA) nss.conf @apache_conf@/../conf.d/nss.conf; \ fi \ else \ if [ ! -f @apache_conf@/nss.conf ]; then \ $(INSTALL_DATA) nss.conf @apache_conf@/nss.conf; \ fi \ fi if [ -d @apache_conf@/../conf.d ]; then \ if [ -f @apache_conf@/../conf.d/ssl.conf ]; then \ mv @apache_conf@/../conf.d/ssl.conf @apache_conf@/../conf.d/ssl.conf.old; \ fi \ else \ if [ -f @apache_conf@/ssl.conf ]; then \ mv @apache_conf@/ssl.conf @apache_conf@/ssl.conf.old; \ fi \ fi install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(apache_bin) @list='$(bin_PROGRAMS)'; for p in $$list; do \ if test -f $$p; then \ echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(apache_bin)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(apache_bin)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ else :; fi; \ done @echo "" @echo "********************** NOTE **************************" @echo "To create a certificate database with a self-signed" @echo "certificate, use the gencert program that comes with" @echo "mod_nss." @echo "********************** NOTE **************************" @echo "" nss_expr_scan.c: nss_expr_scan.l nss_expr_parse.h $(LEX) -Pnss_expr_yy -s -B nss_expr_scan.l sed -e '/$$Header:/d' nss_expr_scan.c && rm -f lex.nss_expr_yy.c nss_expr_parse.c nss_expr_parse.h: nss_expr_parse.y $(YACC) -d nss_expr_parse.y sed -e 's;yy;nss_expr_yy;g' \ -e '/#if defined(c_plusplus) || defined(__cplusplus)/,/#endif/d' \ nss_expr_parse.c && rm -f y.tab.c sed -e 's;yy;nss_expr_yy;g' \ nss_expr_parse.h && rm -f y.tab.h LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) $(EXTRA_CPPFLAGS) LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ MAINTAINERCLEANFILES = \ *~ \ Makefile.in \ aclocal.m4 \ config.guess \ config.sub \ configure \ depcomp \ install-sh \ ltmain.sh \ missing \ ylwrap EXTRA_DIST = *.h *.8 LICENSE test docs check: cd test; \ rm -rf work; \ nosetests -v test_cipher.py; \ if [ `id -u` != 0 ]; then \ ./setup.sh -s 1; \ nosetests -v test.py; \ sleep 5; \ rm -rf work; \ ./setup.sh sql: -s 1; \ DBPREFIX=sql: nosetests -v test.py; \ cd ..; \ else \ echo "Skipping live tests as they cannot be run as root"; \ fi checksni: cd test; \ rm -rf work; \ ./setup.sh -s 25; \ nosetests -v testsni.py; \ cd .. .PHONY: all test clean mod_nss-1.0.12/NEWS000066400000000000000000000000001260357105600137270ustar00rootroot00000000000000mod_nss-1.0.12/NOTICE000066400000000000000000000013711260357105600141500ustar00rootroot00000000000000This product includes software developed by The Apache Software Foundation (http://www.apache.org/). Portions of this software were developed at the National Center for Supercomputing Applications (NCSA) at the University of Illinois at Urbana-Champaign. This software contains code derived from the RSA Data Security Inc. MD5 Message-Digest Algorithm, including various modifications by Spyglass Inc., Carnegie Mellon University, and Bell Communications Research, Inc (Bellcore). Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England. The original software is available from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ mod_nss-1.0.12/README000066400000000000000000000125751260357105600141340ustar00rootroot00000000000000SYNOPSIS This Apache module provides strong cryptography for the Apache 2.4 webserver via the Secure Sockets Layer (v3) and Transport Layer Security (TLS v1) protocols by the help of the SSL/TLS implementation library NSS This module is based heavily on the mod_ssl package. In fact, it's more a conversion than anything else. BUILDING To build this you'll need NSPR 4.9.+ and NSS 3.14.+. It may work with earlier versions but these are recommended (or tested). These can be retrieved from http://www.mozilla.org/. The --with-nspr and --with-nss tags require that the package be installed in the same parent directory (e.g. /opt/nspr, /usr/local/nspr, etc). It will look in this parent for include/, lib/, etc. If --with-nss or --with-nspr are not passed configure will look for the mozilla-[nss|nspr]-devel packages and use the libraries with that if found. It is strongly recommended that the mozilla.org version be used instead. Build and install those packages somewhere then configure the module with something like: % autoreconf -ivf % ./configure --with-apxs[=/path/to/apxs/] --with-nspr=/path/to/nspr/ --with-nss=/path/to/nss/ % gmake all install You only need to use =/path/to/apxs if apxs isn't in your path or if you want to install into a specific Apache installation. This will install a sample configuration file nss.conf. You'll need to do some hand-editing as well to tell Apache to read this file. To httpd.conf add (anywhere is fine): Include conf/nss.conf You'll need to change the default ports in nss.conf from 443 to something else if you aren't starting the server as root. CONFIGURING NSS You'll need to create an NSS database and get a server certificate installed. A script, gencerts, is included to help get things going with a self-signed certificate. This is a *BAD* idea and you shouldn't use this. It is for demonstration purposes only. As a matter of policy, users should not get used to accepting a SSL certifiate signed by an unknown or untrusted issuer. The result of the gencert script is an NSS database that contains a self-signed CA, a server certificate (nickname Server-Cert) and a client certificate (alpha). The client certificate is generated to make testing client authentication simpler. You can store the token passwords in a file so you aren't prompted during startup (so you can do unattended starts, for example). To do this, set the file that will store the token passwords in the NSSPassPhraseDialog attribute in nss.conf ala: NSSPassPhraseDialog file:/path/to/password.conf The format of the file for a non-hardware token is tokenname:password. A sample for the internal software token is like: internal:netscape BUILT-IN ROOT CAs NSS provides a list of built-in CA's (VeriSign, Thawte, etc). This takes the form of a shared library, libnssckbi.so. If this library is placed in the same directory as the certificate database then it will be loaded automatically when the server starts. DOCUMENTATION See docs/mod_nss.html for additional information. For NSS documentation, see http://www.mozilla.org/projects/security/pki/nss/ REQUESTING A CERTIFICATE You can use the provided gencert utility as a template for generating a CA and a sample user and server certificate. Alterntaively, the NSS command-line tools may be used to generate a certificate request suitable for submission to a local CA or a commerical CA like Verisign, and install the issued certificate into your local database. A sample request may look something like this. This assumes that your certificate database directory (NSSCertificateDatabase) is set to /etc/httpd/alias Step 1 Create the database. This assumes you want your certificate database in /etc/httpd/alias % cd /etc/httpd % mkdir alias % cd alias % certutil -N -d . Step 2 Generate a PKCS#10 certificate request % certutil -R -d . -s "CN=test.example.com, O=Example, c=US" -o certreq.txt -a The file certreq.txt contains an ASCII representation of the certificate request and may be submitted to a CA for approval. Step 3 The CA has issued your certificate. In this example, you have the PKCS#7 (ASCII) copy in the file cert.txt. You have a copy of the CA certificate chain in ca.txt. % certutil -A -d . -n Server-Cert -t "u,u,u" -a < cert.txt % certutil -A -d . -n "My CA" -t "CTu,CTu,CTu" -a < ca.txt Step 4 Verify that the certificate and CA are installed correctly % certutil -V -u V -d . -n Server-Cert TESTING A few simple scripts are provided to stand up an in-tree Apache instance against which some basic tests can be run to validate that the in-tree library works. From the source tree run: % make check The tests are run twice. Once with the old-style database and once using the sqlite database format. See https://wiki.mozilla.org/NSS_Shared_DB This is controlled by the environment variable DBPREFIX which needs to be set to sql: when using the newer format for the tests. A test for the OpenSSL-compatibility is also executed. It tries to compare the output of `openssl ciphers ` with the equivalent from mod_nss. This may vary by release of OpenSSL and what ciphers are available in NSS. The test suite requires python >= 2.7.10 and python-requests > 2.7.0. There is a very small SNI suite included as well. To run it you need to add www[1..25].example.com to your /etc/hosts pointing to your IP address. Then run: % make checksni mod_nss-1.0.12/TODO000066400000000000000000000001331260357105600137270ustar00rootroot00000000000000- Once NSS fully supports the SNI TLS extension, add that. - Add support for OCSP stapling mod_nss-1.0.12/acinclude.m4000066400000000000000000000066141260357105600154420ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_define.html # =========================================================================== # # SYNOPSIS # # AC_CHECK_DEFINE([symbol], [ACTION-IF-FOUND], [ACTION-IF-NOT]) # AX_CHECK_DEFINE([includes],[symbol], [ACTION-IF-FOUND], [ACTION-IF-NOT]) # # DESCRIPTION # # Complements AC_CHECK_FUNC but it does not check for a function but for a # define to exist. Consider a usage like: # # AC_CHECK_DEFINE(__STRICT_ANSI__, CFLAGS="$CFLAGS -D_XOPEN_SOURCE=500") # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 8 AU_ALIAS([AC_CHECK_DEFINED], [AC_CHECK_DEFINE]) AC_DEFUN([AC_CHECK_DEFINE],[ AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl AC_CACHE_CHECK([for $1 defined], ac_var, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ #ifdef $1 int ok; #else choke me #endif ]])],[AS_VAR_SET(ac_var, yes)],[AS_VAR_SET(ac_var, no)])) AS_IF([test AS_VAR_GET(ac_var) != "no"], [$2], [$3])dnl AS_VAR_POPDEF([ac_var])dnl ]) AU_ALIAS([AX_CHECK_DEFINED], [AX_CHECK_DEFINE]) AC_DEFUN([AX_CHECK_DEFINE],[ AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$2_$1])dnl AC_CACHE_CHECK([for $2 defined in $1], ac_var, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <$1>]], [[ #ifdef $2 int ok; #else choke me #endif ]])],[AS_VAR_SET(ac_var, yes)],[AS_VAR_SET(ac_var, no)])) AS_IF([test AS_VAR_GET(ac_var) != "no"], [$3], [$4])dnl AS_VAR_POPDEF([ac_var])dnl ]) AC_DEFUN([AX_CHECK_FUNC], [AS_VAR_PUSHDEF([ac_var], [ac_cv_func_$2])dnl AC_CACHE_CHECK([for $2], ac_var, dnl AC_LANG_FUNC_LINK_TRY [AC_LINK_IFELSE([AC_LANG_PROGRAM([$1 #undef $2 char $2 ();],[ char (*f) () = $2; return f != $2; ])], [AS_VAR_SET(ac_var, yes)], [AS_VAR_SET(ac_var, no)])]) AS_IF([test AS_VAR_GET(ac_var) = yes], [$3], [$4])dnl AS_VAR_POPDEF([ac_var])dnl ])# AC_CHECK_FUNC mod_nss-1.0.12/configure.ac000066400000000000000000000155771260357105600155470ustar00rootroot00000000000000# Required initializer AC_INIT([mod_nss],[1.0.12]) m4_include([acinclude.m4]) # Automake initialization AM_INIT_AUTOMAKE # Add a test for a compiler. AC_PROG_CC AM_PROG_CC_C_O AM_PROG_LIBTOOL AC_CONFIG_HEADERS([config.h]) # Check for header files AC_HEADER_STDC AC_CHECK_HEADERS( \ unistd.h ) # Check for typedefs, structures, and compiler characteristics. AC_C_CONST # Find lex and yacc (or flex and bison) AC_PROG_YACC AC_PROG_LEX AC_DECL_YYTEXT AC_MSG_CHECKING(for ECC) AC_ARG_ENABLE(ecc, [ --enable-ecc enable Elliptical Curve Cyptography (default=no)], ecc=$enableval, ecc=no) if test $ecc = yes; then AC_MSG_RESULT(yes) extra_cppflags="$extra_cppflags -DNSS_ENABLE_ECC" else AC_MSG_RESULT(no) fi #AM_CONDITIONAL(ECC, test x$ecc = xyes) AC_CHECKING(for apr-config) # check for --with-apr-config AC_MSG_CHECKING(for --with-apr-config) AC_ARG_WITH(apr-config, [ --with-apr-config Use apr-config to determine the APR directory], [ if test -x "$withval" then AC_MSG_RESULT([using $withval]) APR_CONFIG=$withval fi ], AC_MSG_RESULT(no)) if test -z "$APR_CONFIG" ; then AC_MSG_CHECKING(for apr-1-config and apr-config) AC_PATH_PROGS(APR_CONFIG, apr-1-config apr-config, NO_APR_CONFIG, [$PATH:/usr/local/apache/sbin:/usr/sbin]) fi if test -n "$APR_CONFIG"; then AC_MSG_RESULT([using $APR_CONFIG. Use --with-apr-config to specify another.]) apr_inc=`$APR_CONFIG --includes` else AC_MSG_ERROR([neither apr-config nor apr-1-config were not found. use --with-apr-config to specify it.]) fi AC_CHECKING(for apxs) # check for --with-apxs AC_MSG_CHECKING(for --with-apxs) AC_ARG_WITH(apxs, [ --with-apxs=PATH Path to apxs], [ if test -x "$withval" then AC_MSG_RESULT([using $withval]) APXS=$withval else echo AC_MSG_ERROR([$withval not found or not executable]) fi ], AC_MSG_RESULT(no)) # if no apxs found yet, check /usr/local/apache/sbin # since it's the default Apache location if test -z "$APXS"; then AC_MSG_CHECKING(for apxs in /usr/local/apache/sbin and /usr/sbin) AC_PATH_PROG(APXS, apxs, NO_APXS, [/usr/local/apache/sbin:/usr/sbin:$PATH]) if test -x $APXS; then AC_MSG_RESULT([found $APXS. Use --with-apxs to specify another.]) else AC_MSG_RESULT(no) fi fi # and finally if test -z "$APXS"; then AC_MSG_ERROR([apxs was not found. use --with-apxs to specify it.]) fi # Get some variables we need for Makefile.in apache_inc=`$APXS -q INCLUDEDIR` apache_conf=`$APXS -q SYSCONFDIR` apache_prefix=`$APXS -q PREFIX` apache_bin=`$APXS -q SBINDIR` extra_cppflags="$extra_cppflags `$APXS -q EXTRA_CPPFLAGS`" if ! test -f "$apache_inc/apr.h"; then if test -z "$apr_inc"; then AC_MSG_ERROR([apr.h is not in your Apache include dir as reported by apxs. Use --with-apr-config to have apr-config tell us where to find it.]) fi fi AC_CHECKING(for NSPR) # check for --with-nspr AC_MSG_CHECKING(for --with-nspr) AC_ARG_WITH(nspr, [ --with-nspr=PATH Netscape Portable Runtime (NSPR) directory], [ if test -e "$withval"/include/nspr.h -a -d "$withval"/lib then AC_MSG_RESULT([using $withval]) NSPRDIR=$withval nspr_inc="-I$NSPRDIR/include" nspr_lib="-L$NSPRDIR/lib" else echo AC_MSG_ERROR([$withval not found]) fi ], AC_MSG_RESULT(no)) # check for --with-nspr-inc AC_MSG_CHECKING(for --with-nspr-inc) AC_ARG_WITH(nspr-inc, [ --with-nspr-inc=PATH Netscape Portable Runtime (NSPR) include file directory], [ if test -e "$withval"/nspr.h then AC_MSG_RESULT([using $withval]) nspr_inc="-I$withval" else echo AC_MSG_ERROR([$withval not found]) fi ], AC_MSG_RESULT(no)) # check for --with-nspr-lib AC_MSG_CHECKING(for --with-nspr-lib) AC_ARG_WITH(nspr-lib, [ --with-nspr-lib=PATH Netscape Portable Runtime (NSPR) library directory], [ if test -d "$withval" then AC_MSG_RESULT([using $withval]) nspr_lib="-L$withval" else echo AC_MSG_ERROR([$withval not found]) fi ], AC_MSG_RESULT(no)) # if NSPR is not found yet, try pkg-config # last resort if test -z "$nspr_inc" -o -z "$nspr_lib"; then AC_MSG_CHECKING(for nspr with pkg-config) AC_PATH_PROG(PKG_CONFIG, pkg-config) if test -n "$PKG_CONFIG"; then if $PKG_CONFIG --exists nspr; then nspr_inc=`$PKG_CONFIG --cflags-only-I nspr` nspr_lib=`$PKG_CONFIG --libs-only-L nspr` else AC_MSG_ERROR([NSPR not found, specify with --with-nspr.]) fi fi fi AC_CHECKING(for NSS) # check for --with-nss AC_MSG_CHECKING(for --with-nss) AC_ARG_WITH(nss, [ --with-nss=PATH Network Security Services (NSS) directory], [ if test -e "$withval"/include/nss.h -a -d "$withval"/lib then AC_MSG_RESULT([using $withval]) NSSDIR=$withval nss_inc="-I$NSSDIR/include" nss_lib="-L$NSSDIR/lib" else echo AC_MSG_ERROR([$withval not found]) fi ], AC_MSG_RESULT(no)) # check for --with-nss-inc AC_MSG_CHECKING(for --with-nss-inc) AC_ARG_WITH(nss-inc, [ --with-nss-inc=PATH Network Security Services (NSS) include directory], [ if test -e "$withval"/nss.h then AC_MSG_RESULT([using $withval]) nss_inc="-I$withval" else echo AC_MSG_ERROR([$withval not found]) fi ], AC_MSG_RESULT(no)) # check for --with-nss-lib AC_MSG_CHECKING(for --with-nss-lib) AC_ARG_WITH(nss-lib, [ --with-nss-lib=PATH Network Security Services (NSS) library directory], [ if test -d "$withval" then AC_MSG_RESULT([using $withval]) nss_lib="-L$withval" else echo AC_MSG_ERROR([$withval not found]) fi ], AC_MSG_RESULT(no)) # if NSS is not found yet, try pkg-config # last resort if test -z "$nss_inc" -o -z "$nss_lib"; then AC_MSG_CHECKING(for nss with pkg-config) AC_PATH_PROG(PKG_CONFIG, pkg-config) if test -n "$PKG_CONFIG"; then if $PKG_CONFIG --exists nss; then nss_inc=`$PKG_CONFIG --cflags-only-I nss` nss_lib=`$PKG_CONFIG --libs-only-L nss` else AC_MSG_ERROR([NSS not found, specify with --with-nss.]) fi fi fi nspr_dir=`echo "$nspr_lib" | sed 's/\/lib[[/]]*$//' | sed 's/-L//'` nss_dir=`echo "$nss_lib" | sed 's/\/lib[[/]]*$//' | sed 's/-L//'` AX_CHECK_DEFINE(nss3/sslproto.h, TLS_RSA_WITH_AES_128_GCM_SHA256, gcm=$enableval, gcm=no) if test $gcm = yes; then extra_cppflags="$extra_cppflags -DENABLE_GCM" echo "ENABLE_GCM=1" > test/variable.py else echo "ENABLE_GCM=0" > test/variable.py fi AX_CHECK_DEFINE(nss3/sslproto.h, TLS_RSA_WITH_AES_256_GCM_SHA384, sha384=$enableval, sha384=no) if test $sha384 = yes; then extra_cppflags="$extra_cppflags -DENABLE_SHA384" echo "ENABLE_SHA384=1" >> test/variable.py else echo "ENABLE_SHA384=0" >> test/variable.py fi # Substitute values AC_SUBST(APXS) AC_SUBST(apr_inc) AC_SUBST(apache_inc) AC_SUBST(apache_conf) AC_SUBST(apache_prefix) AC_SUBST(apache_bin) AC_SUBST(nspr_inc) AC_SUBST(nspr_lib) AC_SUBST(nss_inc) AC_SUBST(nss_lib) AC_SUBST(nspr_dir) AC_SUBST(nss_dir) AC_SUBST(extra_cppflags) # Write config.status and the Makefile AC_OUTPUT(Makefile nss.conf gencert) chmod +x gencert mod_nss-1.0.12/docs/000077500000000000000000000000001260357105600141725ustar00rootroot00000000000000mod_nss-1.0.12/docs/mod_nss.html000066400000000000000000002020651260357105600165270ustar00rootroot00000000000000 mod_nss

mod_nss

Table of Contents

Introduction
Building
Installation
Certificate Generation
Server Startup
Migration
Configuration Directives
Environment Variables
Database Management
Why is SSLv2 disabled?
Frequently Asked Questions
Sample Use Cases

Introduction

The mod_ssl package was created in April 1998 by Ralf S. Engelschall and was originally derived from the Apache-SSL package developed by Ben Laurie. It is licensed under the Apache 2.0 license.

mod_nss is based directly on the mod_ssl package from Apache 2.0.54. It is a conversion from using OpenSSL calls to using NSS calls instead.

Building

Refer to the README file included with the distribution.

To build you'll need NSPR 4.4.1 or above and NSS 3.9.2 or above. It may work with earlier versions but these are recommended (or tested). These can be retrieved from http://www.mozilla.org/. The --with-nspr and --with-nss options require that the package be installed in the same parent directory (e.g. /opt/nspr, /usr/local/nspr, etc). It will look in this parent for include/ and lib/, etc.

To build with ECC support you need NSPR 4.6.2 or higher and NSS 3.11.2 or higher.

You will also need the NSS and NSPR directories in your library search path (either /etc/ld.so.conf or LD_LIBRARY_PATH) to link and run the module.

Run the configure script. The following mod_nss-specific options are available:

Option
Description
--with-nss=[PATH]
The file system path to the NSS installation. The assumption is that this has the layout of: PATH/lib, PATH/include, etc.
--with-nss-inc=PATH
The file system path to the NSS include directory (e.g. /usr/local/include/nss3)
--with-nss-lib=PATH
The file system path to the NSS lib directory (e.g. /usr/local/lib)
--with-nspr=[PATH]
The file system path of the NSPR installation. The assumption is that this has the layout of: PATH/lib, PATH/include, etc.
--with-nspr-inc=PATH
The file system path to the NSPR include directory (e.g. /usr/local/include/nspr4)
--with-nspr-lib=PATH
The file system path to the NSPR lib directory (e.g. /usr/local/lib)
--with-apxs=[PATH]
The location of the apxs binary of the Apache you want to install the module into.
--with-apr-config=[PATH] The location of apr-config which tells us where the APR include files and libraries are located
--enable-ecc
Enable Elliptical Curve Cryptography. Disabled by default.

 If --with-nss or --with-nspr are not passed configure will look for the [nss|nspr]-devel packages and use the libraries with that if found.

 It is strongly recommended that the mozilla.org version be used.

 Build and install those packages somewhere then configure the module with something like:

 % ./configure --with-apxs=/path/to/apxs/ --with-nspr=/path/to/nspr/ --with-nss=/path/to/nss/
 % gmake


 This will create a sample configuration file nss.conf. By default this is installed during the installation process.

Installation

The make install target uses apxs to install the module into Apache. This automatically copies the mod_nss shared library to the appropriate location and updates Apache's httpd.conf so that the module will be loaded during the next restart.

It also tries to rename ssl.conf to ssl.conf.old. The assumption is that mod_nss is replacing mod_ssl. They can co-exist as long as they are listening on separate ports.

The mod_nss configuration file, nss.conf, is copied into the Apache configuration directory (as reported by apxs). You may need to make a manual change to httpd.conf to load this file. If you have a Red Hat-style Apache installation with a conf.d just move nss.conf there. It will be automatically loaded. Otherwise you will need to add the following line to httpd.conf (location relative to httpd.conf):

Include conf/nss.conf

This has Apache load the mod_nss configuration file, nss.conf. It is here that you will setup your VirtualServer entries to and configure your SSL servers. If you have a certificate with Subject Alternative Names then you can configure separate VirtualServer entries for eacon one.

Certificate Generation

A ksh script, gencert, is included to automatically generate a self-signed CA plus one server certificate. This is fine for testing purposes but it is strongly recommended that a real server certificate be obtained from a real CA before moving a mod_nss server into production. Users should be expected to cancel any request to a secure server signed by an unknown issuer.

gencert takes one argument, the path to the location of the certificate database. A fair amount of output is generated so you can follow what is going on. For the most part most don't need to bother with the details.

The certificate database password is httptest.

A sample run is:
# mkdir /etc/httpd/nss
# ./gencert /etc/httpd/nss

#####################################################################
Generating new server certificate and key database. The password
is httptest
#####################################################################

#####################################################################
Generating self-signed client CA certificate
#####################################################################

Generating key.  This may take a few moments...

[ Lots of output removed ]
You should now have the following files:
/etc/httpd/nss/cert8.db
/etc/httpd/nss/key3.db
/etc/httpd/nss/secmod.db
These 3 files make up an NSS certificate database.

If you have a sql: prefix on the path, like sql:/etc/httpd/nss, then it will generate an SQLite NSS database consisting of the following files:
/etc/httpd/nss/cert9.db
/etc/httpd/nss/key4.db
/etc/httpd/nss/pkcs11.txt

Server Startup

Starting a mod_nss server is no different than starting a mod_ssl server. You will need to authenticate yourself to the security token (e.g. enter the key password). The sample nss.conf is not included in an <IfDefine SSL> so you do not need to use the startssl argument with apachectl.

A sample startup might look like:

% apachectl start
Please enter password for "internal" token:


If you have additional hardware tokens you will be prompted for each token password.

All other output will be written to the Apache log files.

To avoid being prompted for a startup password you can either:
  • Use a password file that contains your token passwords. See NSSPassPhraseDialog for details.
  • Change the internal token password to a blank with:
% modutil -dbdir /path/to/database/directory -changepw "NSS Certificate DB"

Enter the old password then press Enter twice for the new password to blank it out.

Migration

A perl script, migrate.pl, is included to help migrate an existing mod_ssl configuration to work with mod_nss. There is one optional argument, -c, that will try to convert your existing server and CA certificates plus any certificate revocation lists (CRLs) into an NSS certificate database.

The migration script assumes that you are migrating from ssl.conf to nss.conf. The original file is not changed. All comments, spacing and other directives are maintained so if there is no ssl.conf it is possible to migrate httpd.conf to use mod_nss. Simply copy httpd.conf to ssl.conf, run the update, then copy nss.conf to httpd.conf (after making a backup, of couse). This multi-step process gives you a chance to verify that the migration was successful.

Configuration Directives

The following mod_ssl Directives are not applicable to mod_nss:
  • SSLSessionCache
  • SSLMutex
  • SSLCertificateChainFile
  • SSLCARevocationPath
  • SSLCARevocationFile
  • SSLVerifyDepth
  • SSLCryptoDevice
NSSPassPhraseDialog

Authentication is required in order to use the private key in an NSS certificate database. The method of this authentication is specified with the NSSPassPhraseDialog directive. This directive takes one argument specifying the method of authentication:
  • builtin
The user will be prompted to enter the token password for each cryptographic device. This works seemlessly with any hardware tokens used. The default "device" is the internal token provided by the NSS Certificate database itself.
  • file:/path/to/file
The token password(s) may be stored in an ASCII text file which is read during startup so the server can start without user intervention. The format of this file is:

token:password

An example for the internal token is:

internal:secret12

Example

NSSPassPhraseDialog builtin

NSSPassPhraseHelper

When Apache starts it loads and unloads any modules that aren't built-in twice. It loads them once so it can verify that the configuration is ok and then it unloads them and re-loads them again when the server is actually ready to receive connections. After the first module load Apache closes access to the terminal so there is no way to prompt for the NSS token passwords (it would also be annoying to have to authenticate twice). Because the module is loaded and unloaded the NSS certificate database needs to be loaded and unloaded as well, causing any pins entered during the first load to be lost and causing the server to be unstartable.

The solution is the PassPhraseHelper. This is a stand-alone program that also opens the NSS certificate database and stores a copy of the encrypted token password entered during the first load of the NSS module. When mod_nss needs to open the certificate database during subsequent reloads it queries the PassPhraseHelper for the token password.

Example

NSSPassPhraseHelper /path/to/nss_pcache

NSSCertificateDatabase

Specifies the location of the NSS certificate database to be used. An NSS certificate database consists of 3 files: cert8.db, key3.db and secmod.db. cert8.db stores certificates and Certificate Revocation Lists (CRLs), key3.db stores keys and secmod.db stores information about available PKCS#11 modules.

This directive specifies a path, not a filename. To use a sqlite NSS database include the prefix sql: in the path.

Example

NSSCertificateDatabase /etc/httpd/conf/nss
NSSCertificateDatabase sql:/etc/httpd/conf/nss

NSSDBPrefix

Normally a certificate database consists of 3 files: cert8.db, key3.db and secmod.db. This directive allows you to add a named prefix to the filenames of cert8.db and key3.db so you can store multiple databases in one directory.

Example

NSSDBPrefix my-prefix-

You would then need: my-prefix-cert8.db, my-prefix-key3.db and secmod.db

In order to work with files with a prefix using the NSS command-line tools use the -P flag.

NSSSessionCacheSize

Specifies the number of SSL sessions that can be cached.

There is no upper limit.

The default value is 10000.

Example

NSSSessionCacheSize 10000

NSSSessionCacheTimeout

Deprecated.

NSSSession3CacheTimeout

Specifies the number of seconds SSLv3 sessions are cached.

The valid range is 5 - 86400 seconds. A setting outside the valid range is silently constrained.

The default value is 86400 (24 hours).

Example

NSSSession3CacheTimeout 86400

NSSRandomSeed

Configures sources to seed the NSS Random Number Generator (RNG) at startup. Currently this only supports seeding the RNG at startup.

The following sources are available:
  • builtin: Combines the current system time, the current process id and a randomly choosen 128-byte extract of the process stack. This is not a particularly strong source of entropy.
  • file:/path/to/source: Reads from the specified file. If the number of bytes to read is specified it just reads that amount. Be aware that some operating systems block on /dev/random if not enough entropy is available. This means that the server will wait until that data is available to continue startup. These systems generally offer a non-blocking device as well, /dev/urandom.
  • exec:/path/to/program: Executes the given program and takes the stdout of it as the entropy. If the bytes argument is included it reads that many bytes, otherwise it reads until the program exits.
Example

NSSRandomSeed startup builtin
NSSRandomSeed startup /dev/urandom 512
NSSRandomSeed startup /usr/bin/makerandom


NSSEngine

Enables or disables the SSL protocol. This is usually used within a VirtualHost tag to enable SSL for a particular virtual host.

SSL is disabled by default.

Example

NSSEngine on

NSSFIPS

Enables or disables FIPS 140 mode. This replaces the standard internal PKCS#11 module with a FIPS-enabled one. It also forces the enabled protocols to TLSv1.2, TLSv1.1 and TLSv1.0 and disables all ciphers but the FIPS ones. You may still select which ciphers you would like limited to those that are FIPS-certified. Any non-FIPS that are included in the NSSCipherSuite entry are automatically disabled. The allowable ciphers are (with ecc-enabled set):
  • rsa_3des_sha
  • rsa_aes_128_sha
  • rsa_aes_256_sha
  • aes_128_sha_256
  • aes_256_sha_256
  • rsa_aes_128_gcm_sha_256
  • fips_3des_sha
  • ecdh_ecdsa_3des_sha
  • ecdh_ecdsa_aes_128_sha
  • ecdh_ecdsa_aes_256_sha
  • ecdhe_ecdsa_3des_sha
  • ecdhe_ecdsa_aes_128_sha
  • ecdhe_ecdsa_aes_256_sha
  • ecdh_rsa_3des_sha
  • ecdh_rsa_aes_128_sha
  • ecdh_rsa_aes_256_sha
  • ecdhe_rsa_3des_sha
  • ecdhe_rsa_aes_128_sha
  • ecdhe_rsa_aes_256_sha
  • ecdhe_ecdsa_aes_128_sha_256
  • ecdhe_rsa_aes_128_sha_256
  • ecdhe_ecdsa_aes_128_gcm_sha_256
  • ecdhe_rsa_aes_128_gcm_sha_256
FIPS is disabled by default.

Example

NSSFIPS on

NSSOCSP

Enables or disables OCSP (Online Certificate Status Protocol). This allows the server to check the validity of a client certificate before accepting it.

OCSP is disabled by default.

Example

NSSOCSP on

NSSCipherSuite

There are two options for configuring the available ciphers. mod_nss provides its own cipher list, a space-separated list of the SSL ciphers used, with the prefix + to enable or - to disable, using the Cipher Name value in the tables below.

Alternatively the mod_nss-style cipher definitions may be used, http://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslciphersuite. The support options are: ALL, COMPLEMENTOFALL, DEFAULT, RSA, EDH, NULL, eNULL, AES, 3DES, DES, RC4, MD5, SHA, SHA1, SHA256, SSLv3, TLSv1, TLSv12, HIGH, MEDIUM, LOW, EXPORT, EXPORT40 and EXPORT56.

If a cipher string value contains a colon it is considered a mod_ssl-style cipher string.

If a cipher string value contains a comma it is considered a mod_nss-style cipher string.

If it contains neither then mod_nss first tries to apply OpenSSL ciphers then NSS ciphers.

All ciphers are disabled by default.

Available ciphers are:

Cipher Name
NSS Cipher definition
Protocol
rsa_3des_sha
TLS_RSA_WITH_3DES_EDE_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_des_sha
TLS_RSA_WITH_DES_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_null_md5
TLS_RSA_WITH_NULL_MD5
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_null_sha
TLS_RSA_WITH_NULL_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_rc2_40_md5 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_rc4_128_md5 TLS_RSA_WITH_RC4_128_MD5
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_rc4_128_sha TLS_RSA_WITH_RC4_128_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_rc4_40_md5 TLS_RSA_EXPORT_WITH_RC4_40_MD5
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
fips_des_sha
SSL_RSA_FIPS_WITH_DES_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
fips_3des_sha
SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_des_56_sha TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_rc4_56_sha TLS_RSA_EXPORT1024_WITH_RC4_56_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_aes_128_sha
TLS_RSA_WITH_AES_128_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
rsa_aes_256_sha
TLS_RSA_WITH_AES_256_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
camelia_128_sha
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
camelia_256_sha
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
SSLv3/TLSv1.0/TLSv1.1/TLSv1.2
null_sha_256
TLS_RSA_WITH_NULL_SHA256
TLSv1.2
aes_128_sha_256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLSv1.2
aes_256_sha_256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLSv1.2
rsa_aes_128_gcm_sha_256
TLS_RSA_WITH_AES_128_GCM_SHA256
TLSv1.2

Additionally there are a number of ECC ciphers:

Cipher Name
NSS Cipher Definition
Protocol
ecdh_ecdsa_null_sha TLS_ECDH_ECDSA_WITH_NULL_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_ecdsa_rc4_128_sha TLS_ECDH_ECDSA_WITH_RC4_128_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_ecdsa_3des_sha TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_ecdsa_aes_128_sha TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_ecdsa_aes_256_sha TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_ecdsa_null_sha TLS_ECDHE_ECDSA_WITH_NULL_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_ecdsa_rc4_128_sha TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_ecdsa_3des_sha TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_ecdsa_aes_128_sha TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_ecdsa_aes_256_sha TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_rsa_null_sha TLS_ECDH_RSA_WITH_NULL_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_rsa_128_sha TLS_ECDH_RSA_WITH_RC4_128_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_rsa_3des_sha TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_rsa_aes_128_sha TLS_ECDH_RSA_WITH_AES_128_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_rsa_aes_256_sha TLS_ECDH_RSA_WITH_AES_256_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
echde_rsa_null TLS_ECDHE_RSA_WITH_NULL_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_rsa_rc4_128_sha TLS_ECDHE_RSA_WITH_RC4_128_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_rsa_3des_sha TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_rsa_aes_128_sha TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_rsa_aes_256_sha TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_anon_null_sha TLS_ECDH_anon_WITH_NULL_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_anon_rc4_128sha TLS_ECDH_anon_WITH_RC4_128_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_anon_3des_sha TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_anon_aes_128_sha TLS_ECDH_anon_WITH_AES_128_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdh_anon_aes_256_sha TLS_ECDH_anon_WITH_AES_256_CBC_SHA TLSv1.0/TLSv1.1/TLSv1.2
ecdhe_ecdsa_aes_128_sha_256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLSv1.2
ecdhe_rsa_aes_128_sha_256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLSv1.2
ecdhe_ecdsa_aes_128_gcm_sha_256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLSv1.2
ecdhe_rsa_aes_128_gcm_sha_256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLSv1.2

Example

NSSCipherSuite +rsa_3des_sha,-rsa_des_56_sha,+rsa_des_sha,-rsa_null_md5,-rsa_null_sha,-rsa_rc2_40_md5,+rsa_rc4_128_md5,-rsa_rc4_128_sha,-rsa_rc4_40_md5,-rsa_rc4_56_sha,-fips_des_sha, +fips_3des_sha,-rsa_aes_128_sha,-rsa_aes_256_sha

NSSCipherSuite ALL

NSSCipherSuite rsa_3des_sha

NSSCipherSuite RC4-SHA

NSSProtocol

A comma-separated string that lists the basic protocols that the server can use (and clients may connect with). It doesn't enable a cipher specifically but allows ciphers for that protocol to be used at all.

Options are:
  • SSLv3
  • TLSv1 (legacy only; replaced by TLSv1.0)
  • TLSv1.0
  • TLSv1.1
  • TLSv1.2
  • All
Note that this differs from mod_ssl in that you can't add or subtract protocols.

If no NSSProtocol is specified, mod_nss will default to allowing the use of the TLSv1.0, TLSv1.1 and TLSv1.2 protocols, where TLSv1.0 will be set to be the minimum protocol allowed, and TLSv1.2 will be set to be the maximum protocol allowed.
If values for NSSProtocol are specified, mod_nss will set both the minimum and the maximum allowed protocols based upon these entries allowing for the inclusion of every protocol in-between. For example, if only SSLv3 and TLSv1.1 are specified, SSLv3, TLSv1.0, and TLSv1.1 will all be allowed, as NSS utilizes protocol ranges to accept all protocols inclusively (TLSv1.1 -> TLSv1.0 -> SSLv3.0), and does not allow exclusion of any protocols in the middle of a range (e. g. - TLSv1.0).

Finally, NSS will always automatically negotiate the use of the strongest possible protocol that has been specified which is acceptable to both sides of a given connection.
SSLv2 is not supported by default at this time.

Example

NSSProtocol SSLv3,TLSv1.0,TLSv1.1

NSSNickname

Specify the nickname to be used for this the server certificate. Certificates stored in an NSS database are referred to using nicknames which makes accessing a specific certificate much easier. It is also possible to specify the certificate DN but it is easier to use a nickname. If the nickname includes spaces then the value needs to be enclosed in double quotes.

Example

NSSNickname Server-Cert
NSSNickname "This contains a space"

NOTE: There is nothing magical about the string "Server-Cert." A nickname can be anything. Historically this was Server-Cert in the Netscape server products that used NSS.

NSSECCNickname

Similar to NSSNickname but designed for use with ECC certificates. This allows you to have both an RSA certificate and an ECC certificate available on the same listening port. This allows newer clients that support ECC to connect with those ciphers but also allows older clients to connect with an RSA cipher.

Example

NSSNickname Server-Cert-ECC

NSSEnforceValidCerts

By default mod_nss will not start up if the server certificate is not valid. This means that if the certificate has expired or is signed by a CA that is not trusted in the NSS certificate database the server will not start. If you would like the server to start anyway you can add this directive to nss.conf and the server will start with just a warning. Not enforcing a valid server certificate is not recommended.

Example

NSSEnforceValidCerts on

NSSVerifyClient

Determines whether Client Certificate Authentication will be requested or required. This may be set in a per-server or per-directory context. At the server level the certificate is requested during the initial SSL handshake. In the per-directry context an SSL renogitation is required and a certificate requested from the client.

Available options are:
  • none: no client certificate is required or requested
  • optional: a client certificate is requested but if one is not available, the connection may continue.
  • require: a valid client certificate is required for the connection to continue.
The mod_ssl option option_no_ca is not supported.

There is no NSSVerifyDepth directive. NSS always verifies the entire certificate chain.

Example

NSSVerifyClient require

NSSSessionTickets

Enables or disables support for TLS Session tickets (RFC 5077). The default is off.

Example

NSSSessionTickets on

NSSUserName

Defines the field in the client certificate which will set the user field in the request. The option FakeBasicAuth (see NSSOptions) must also be set for this to work.

Example

NSSUserName SSL_CLIENT_S_DN_UID

NSSOptions


Control various options in a per-server or per-directory context.
  • FakeBasicAuth: When this option is enabled and NSSUserName is set then the certificate attribute defined in NSSUserName is used to populate the value of r->user in the Apache request object. This equates to the environmant variable REMOTE_USER.
  • StdEnvVars: A standard set of SSL environment variables is created.
  • CompatEnvVars: A no-op. In previous versions of mod_ssl this would set additional environment variables for backwards compatibility with older Apache SSL implementations.
  • ExportCertData: Several additional environment variables are created, SSL_CLIENT_CERT, SSL_CLIENT_CERT_CHAIN[0..n] and SSL_SERVER_CERT. This provides additional certificate information on the client and server to the environment, plus every CA certificate in the client certificate.
  • StrictRequire: Absolutely forces the connection to be forbidden when NSSRequireSSL or NSSRequire aren't met.
  • OptRenegotiate: Allows the SSL connection to be renegotiated using a different configuration. This is designed for a per-directory and is relatively expensive to do. For example, it can be used to force very strong ciphers in particular directories.
All options are disabled by default.

Example:
NSSOptions +FakeBasicAuth
<Files ~ "\.(cgi|shtml)$">
NSSOptions +StdEnvVars
<Files>

NSSRequireSSL

The request is forbidden unless the connection is using SSL. Only available in a per-directory context. This takes no arguments.

Example

NSSRequireSSL

NSSRequire

Provides a regular expression-based access-control mechanism. Access may be restricted (or allowed) based on any number of variables such as components of the client certificate, the remote IP address, etc.

Example

NSSRequire


NSSRenegBufferSize

Configure the amount of memory that will be used for buffering the request body if a per-location SSL renegotiation is required due to changed access control requirements. The value is in bytes. The default is 128K.
If set to 0 then no buffering is done.

Example

NSSRenegBufferSize 262144


NSSSNI

Enables or disables Server Name Identification (SNI) extension check for TLS. This option is enabled by default. To disable SNI, set this to off in the default name-based VirtualHost.

Example

NSSSNI off

NSSStrictSNIVHostCheck

Configures whether a non-SNI client is allowed to access a name-based VirtualHost. If set to on in the default name-based VirtualHost then clients that are SNI unaware cannot access any virtual host. If set to on in any other VirtualHost then SNI unaware clients cannot access this particular virtual host.

Example

NSSStrictSNIVHostCheck off

NSSProxyEngine

Enables or disables mod_nss HTTPS support for mod_proxy.

Example

NSSProxyEngine on

NSSProxyProtocol

Specifies the SSL protocols that may be used in proxy connections. The syntax is identical to NSSProtocol.

Example

NSSProxyProtocol SSLv3

NSSProxyCipherSuite

Specifies the SSL ciphers available for proxy connections. The syntax is identical to NSSCipherSuite.

Example

NSSProxyCipherSuite +rsa_3des_sha,-rsa_null_md5,-rsa_null_sha,+rsa_rc4_128_md5

NSSProxyNickname

The nickname of the client certificate to send if the remote server requests client authentication.

Example

NSSProxyNickname beta

NSSProxyCheckPeerCN

Compare the CN value of the peer certificate with the hostname being requested. If this is set to on, the default, then the request will fail if they do not match. If this is set to off then this comparison is not done. Note that this test is your only protection against a man-in-the-middle attack so leaving this as on is strongly recommended.

Example

NSSProxyCheckPeerCN on

Environment Variables

Quite a few environment variables (for CGI and SSI) may be set depending on the NSSOptions configuration. It can be expensive to set these so it is recommended that they only be set when they will be used (e.g. don't set them on a per-server basis). Here is a list of the variables along with the option used to set them.

Always Set

Name
Description
HTTPS
Set to "on" if HTTPS is being used

+StdEnvVars

Name
Description
SSL_VERSION_INTERFACE
The version of mod_nss the server is running
SSL_VERSION_LIBRARY
The version of NSS that mod_nss was compiled against.
SSL_PROTOCOL
SSLv3, TLSv1.0, TLSv1.1 or TLSv1.2
SSL_CIPHER
The cipher the connection is using
SSL_CIPHER_EXPORT
true if the cipher is an export cipher, false otherwise
SSL_CIPHER_USEKEYSIZE
Number if bits the cipher is using
SSL_CIPHER_ALGKEYSIZE
Max number of bits possible in the cipher
SSL_CLIENT_VERIFY
NONE if no client auth, SUCCESS or FAILED if SSLVerifyCert is set
SSL_CLIENT_V_START
Client certificate validity start time
SSL_CLIENT_V_END
Client certificate validity end time
SSL_CLIENT_V_REMAIN
Number of days that the certificate is valid
SSL_CLIENT_M_VERSION
X.509 version of the client certificate
SSL_CLIENT_M_SERIAL
Serial number of the client certificate
SSL_CLIENT_A_KEY Algorithm used for client key
SSL_CLIENT_A_SIG Algorithm used for the signature of the client key
SSL_CLIENT_S_DN Distinguished Name (DN) of the client certificate
SSL_CLIENT_S_DN_[C,ST,L,O,OU,CN,T,I,G,S,D,UID,Email]
Components of the client certificate. Only those that exist in the certificate are created.
SSL_CLIENT_I_DN
Distinguished Name (DN) of the client certificate issuer
SSL_CLIENT_I_DN_[C,ST,L,O,OU,CN,T,I,G,S,D,UID,Email] Components of the client issuer certificate. Only those that exist in the certificate are created
SSL_SERVER_DN
Distinguished Name (DN) of the server certificate
SSL_SERVER_DN_[C,ST,L,O,OU,CN,T,I,G,S,D,UID,Email] Components of the server certificate. Only those that exist in the certificate are created
SSL_SERVER_I_DN_[C,ST,L,O,OU,CN,T,I,G,S,D,UID,Email] Components of the server issuer certificate. Only those that exist in the certificate are created
SSL_SERVER_M_VERSION
X.509 version of the server certificate
SSL_SERVER_M_SERIAL
Serial number of the server certificate
SSL_SERVER_V_START
Server certificate validity start time
SSL_SERVER_V_END
Server certificate validity end time
SSL_SERVER_A_KEY
Algorithm used for server key
SSL_SERVER_A_SIG
Algorithm used for the signature of the server key
SSL_SESSION_ID
SSL Session ID

+ExportCertData

Name
Description
SSL_SERVER_CERT
The server certificate in PEM format.
SSL_CLIENT_CERT
The client certificate in PEM format (if available)
SSL_CLIENT_CERT_CHAIN_[0..n]
Each certificate in the client certificate chain in PEM format (including the client certificate itself).

Database Management

NSS stores it's certificates and keys in a set of files referred to as the "certificate database." The files by default (with NSS 3.x) are named cert8.db, key3.db and secmod.db. See the NSS documentation at http://www.mozilla.org/projects/security/pki/nss/ for more information on these specific files.

By default the NSS databases use the Berkeley Database format (cert8 and key3). To use the sqlite format (cert9 and key4) either include sql: in all references to the database (-d sql:/path/to/database) or export NSS_DEFAULT_DB_TYPE="sql".

For more details see https://wiki.mozilla.org/NSS_Shared_DB

The NSS database also stores any Certificate Revocation Lists (CRLs).

Several NSS tools are available for managing certificates, keys, PKCS#11 modules and CRLs. These come with the NSS distribution. Here is a brief overview:

Tool
Description
certutil
Generate Certificate Signing Requests, install certificates and manage certificate trust flags.
crlutil
Manage certificate revocation lists (CRLs).
modutil
Manage the database of PKCS11 modules (secmod.db). Add modules and modify the properties of existing modules (such as whether a module is the default provider of some crypto service).
pk12util Import and export keys and certificates in PKCS12 format.

Here are some quick, useful commands. This assumes that the NSPR and NSS libraries are in your LD_LIBRARY_PATH. Certificates may be referred to by either their DN or by a short nickname that is assigned when the certificate is added to the database. The nickname is the preferred method of referring to certificates. All of these commands use the -d option to specify the database location. The default is ~/.netscape and is probably not what you want.

Description
Command
Create a Database
certutil -N -d [path]
List all Certificates
certutil -L -d [path]
Extract a cert (Server-Cert) in ASCII
certutil -L -n Server-Cert -d [path] -a
Extract a cert and key (Server-Cert) in PKCS#12
pk12util -o server.p12 -n Server-Cert -d [path]
Import a cert and key (Import-Me) from PKCS#12
pk12util -i server.p12 -n Import-Me -d [path]

Importing OpenSSL Certificates

If you have existing OpenSSL certificates you can import them into an NSS certificate database.

To import a server certificate (nickname Server-Cert):

% openssl pkcs12 -export -in /path/to/certificate -inkey /path/to/keyfile -out server.p12 -name "Server-Cert" -passout pass:foo
% pk12util -i server.p12 -d [path] -W foo

To import a CA certificate:

% certutil -A -n "myca" -t "CT,," -d [path] -a -i /path/to/cacertificate

To import a CRL:

% openssl crl -in /path/to/crlfile -out /tmp/crl.tmp -inform PEM -outform DER
% crlutil -I -t 1 -d [path] -i /tmp/crl.tmp


To verify that your server certificate was imported properly, you can have NSS validate it:

% certutil -V -n Server-Cert -u V -d .
certutil: certificate is valid

Why is SSLv2 disabled?

All major browsers (Firefox, Internet Explorer, Mozilla, Netscape, Opera, and Safari) support SSLv3 and TLS so there is no need for a web server to support SSLv2. There are some known attacks against SSLv2 that are handled by SSLv3/TLS. SSLv2 also doesn't support useful features like client authentication.

Frequently Asked Questions

Q. Does mod_nss support mod_proxy?

A. Yes but you need to make sure that mod_ssl is not loaded. mod_proxy provides a single interface for SSL providers and mod_nss defers to mod_ssl if it is loaded.

Sample Use Cases

I. Restart Apache using the NSS Internal Software Token

    1. Become the root user.

    2. Install mod_nss.

    3. This use case will utilize the NSS security databases created during installation of mod_nss:

      # certutil -L -d /etc/httpd/alias
      Certificate Nickname                                         Trust Attributes
                                                                   SSL,S/MIME,JAR/XPI
      
      cacert                                                       CTu,Cu,Cu
      Server-Cert                                                  u,u,u
      alpha                                                        u,pu,u
      
      NOTE:   For actual deployments, the administrator should setup their own NSS security databases (e. g. - replace the default mod_nss NSS security databases located in /etc/httpd/alias), populate them with the appropriate certificates set with the proper trust attributes, and apply any changes necessary to the /etc/httpd/conf.d/nss.conf file such that mod_nss uses these NSS security databases.

    4. Use certutil to apply a password to the NSS security databases configured in step 3 above:

      # certutil -W -d /etc/httpd/alias
      Enter Password or Pin for "NSS Certificate DB":
      Enter a password which will be used to encrypt your keys.
      The password should be at least 8 characters long,
      and should contain at least one non-alphabetic character.

      Enter new password:
      Re-enter password:
      Password changed successfully.

    5. Configure mod_nss to use the NSS internal software token:

      Edit /etc/httpd/conf.d/nss.conf:

        Replace:
          NSSPassPhraseDialog builtin
        with:
          NSSPassPhraseDialog file:/etc/httpd/password.conf

          NOTE:   Whenever httpd is invoked as a service/systemd process, the NSSPassPhraseDialog builtin parameter must be changed to point to a file URL in order to allow mod_nss to work with the Apache web server. This is because the mod_nss test for issuing the password prompt Please enter password for "internal" token: on the command line is only displayed when the command isatty(fileno(stdin)) is set to 'true', and when the command is entered from this type of invocation the value is 'false'. In order to see the prompt, one can set the NSSPassPhraseDialog builtin parameter and invoke httpd -D FOREGROUND from the command line.

        If the SSL Server Certificate contained in the NSS security database is an RSA certificate, make certain that the NSSNickname parameter is uncommented and matches the nickname displayed in step 3 above:
          NSSNickname Server-Cert

        If the SSL Server Certificate contained in the NSS security database is an ECC certificate, make certain that the NSSECCNickname parameter is uncommented and matches the nickname displayed in step 3 above:
          NSSECCNickname Server-Cert

        Make certain that the NSSCertificateDatabase parameter is uncommented and points to the NSS security databases directory configured in step 3 above:
          NSSCertificateDatabase /etc/httpd/alias

      Create the /etc/httpd/password.conf file:

        Add:
          internal:<password>
        Replacing '<password>' with the password that was applied to the NSS security databases in step 4 above.

      Apply the appropriate ownership and permissions to the /etc/httpd/password.conf file:

        # chgrp apache /etc/httpd/password.conf

        # chmod 640 /etc/httpd/password.conf

        # ls -l /etc/httpd/password.conf
        -rw-r-----. 1 root apache 18 Nov 27 14:05 /etc/httpd/password.conf

    6. Restart the Apache server:

      # service httpd restart
      Redirecting to /bin/systemctl restart httpd.service
      # service httpd status
      Redirecting to /bin/systemctl status  httpd.service
      httpd.service - The Apache HTTP Server
         Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled)
         Active: active (running) since Wed 2013-11-27 15:25:48 PST; 1min 11s ago
        Process: 20804 ExecStop=/bin/kill -WINCH ${MAINPID} (code=exited, status=0/SUCCESS)
       Main PID: 20807 (httpd)
         Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
         CGroup: name=systemd:/system/httpd.service
                 |_____20807 /usr/sbin/httpd -DFOREGROUND
                 |_____20808 /usr/libexec/nss_pcache 10027086 off /etc/httpd/alias
                 |_____20809 /usr/sbin/httpd -DFOREGROUND
                 |_____20810 /usr/sbin/httpd -DFOREGROUND
                 |_____20811 /usr/sbin/httpd -DFOREGROUND
                 |_____20812 /usr/sbin/httpd -DFOREGROUND
                 |_____20813 /usr/sbin/httpd -DFOREGROUND
      
      Nov 27 15:25:48 server.example.com systemd[1]: Started The Apache HTTP Server.
      

II. Restart Apache using the NSS FIPS Software Token

    1. Become the root user.

    2. Install mod_nss.

    3. This use case will utilize the NSS security databases created during installation of mod_nss:

      # certutil -L -d /etc/httpd/alias
      Certificate Nickname                                         Trust Attributes
                                                                   SSL,S/MIME,JAR/XPI
      
      cacert                                                       CTu,Cu,Cu
      Server-Cert                                                  u,u,u
      alpha                                                        u,pu,u
      
      NOTE:   For actual deployments, the administrator should setup their own NSS security databases (e. g. - replace the default mod_nss NSS security databases located in /etc/httpd/alias), populate them with the appropriate certificates set with the proper trust attributes, and apply any changes necessary to the /etc/httpd/conf.d/nss.conf file such that mod_nss uses these NSS security databases.

    4. Use certutil to apply a password to the NSS security databases configured in step 3 above:

      # certutil -W -d /etc/httpd/alias
      Enter Password or Pin for "NSS Certificate DB":
      Enter a password which will be used to encrypt your keys.
      The password should be at least 8 characters long,
      and should contain at least one non-alphabetic character.

      Enter new password:
      Re-enter password:
      Password changed successfully.

    5. Configure mod_nss to use the NSS FIPS software token:

      Edit /etc/httpd/conf.d/nss.conf:

        Replace:
          NSSPassPhraseDialog builtin
        with:
          NSSPassPhraseDialog file:/etc/httpd/password.conf

          NOTE:   Whenever httpd is invoked as a service/systemd process, the NSSPassPhraseDialog builtin parameter must be changed to point to a file URL in order to allow mod_nss to work with the Apache web server. This is because the mod_nss test for issuing the password prompt Please enter password for "NSS FIPS 140-2 Certificate DB" token: on the command line is only displayed when the command isatty(fileno(stdin)) is set to 'true', and when the command is entered from this type of invocation the value is 'false'. In order to see the prompt, one can set the NSSPassPhraseDialog builtin parameter and invoke httpd -D FOREGROUND from the command line.

        To enable FIPS mode for mod_nss, add the following parameter:
          NSSFIPS on
        after the line marked:
          NSSEngine on

        If the SSL Server Certificate contained in the NSS security database is an RSA certificate, make certain that the NSSNickname parameter is uncommented and matches the nickname displayed in step 3 above:
          NSSNickname Server-Cert

        If the SSL Server Certificate contained in the NSS security database is an ECC certificate, make certain that the NSSECCNickname parameter is uncommented and matches the nickname displayed in step 3 above:
          NSSECCNickname Server-Cert

        Make certain that the NSSCertificateDatabase parameter is uncommented and points to the NSS security databases directory configured in step 3 above:
          NSSCertificateDatabase /etc/httpd/alias

      Create the /etc/httpd/password.conf file:

        Add:
          NSS FIPS 140-2 Certificate DB:<password>
        Replacing '<password>' with the password that was applied to the NSS security databases in step 4 above.

        IMPORTANT:   Notice that since the NSS FIPS software token is being used, the contents of the /etc/httpd/password.conf file references the password for the NSS FIPS software token (NSS FIPS 140-2 Certificate DB:<password>) rather than the NSS internal software token (internal:<password>).

      Apply the appropriate ownership and permissions to the /etc/httpd/password.conf file:

        # chgrp apache /etc/httpd/password.conf

        # chmod 640 /etc/httpd/password.conf

        # ls -l /etc/httpd/password.conf
        -rw-r-----. 1 root apache 39 Nov 27 15:48 /etc/httpd/password.conf

    6. Restart the Apache server:

      # service httpd restart
      Redirecting to /bin/systemctl restart httpd.service
      # service httpd status
      Redirecting to /bin/systemctl status  httpd.service
      httpd.service - The Apache HTTP Server
         Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled)
         Active: active (running) since Wed 2013-11-27 16:26:07 PST; 4s ago
        Process: 21296 ExecStop=/bin/kill -WINCH ${MAINPID} (code=exited, status=0/SUCCESS)
       Main PID: 21299 (httpd)
         Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
         CGroup: name=systemd:/system/httpd.service
                 |_____21299 /usr/sbin/httpd -DFOREGROUND
                 |_____21300 /usr/libexec/nss_pcache 10289231 on /etc/httpd/alias
                 |_____21340 /usr/sbin/httpd -DFOREGROUND
                 |_____21341 /usr/sbin/httpd -DFOREGROUND
                 |_____21342 /usr/sbin/httpd -DFOREGROUND
      
      Nov 27 16:26:07 server.example.com systemd[1]: Started The Apache HTTP Server.
      
mod_nss-1.0.12/gencert.8000066400000000000000000000045401260357105600147650ustar00rootroot00000000000000.\" A man page for gencert .\" .\" Licensed under the Apache License, Version 2.0 (the "License"); .\" you may not use this file except in compliance with the License. .\" You may obtain a copy of the License at .\" .\" http://www.apache.org/licenses/LICENSE-2.0 .\" .\" Unless required by applicable law or agreed to in writing, software .\" distributed under the License is distributed on an "AS IS" BASIS, .\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" See the License for the specific language governing permissions and .\" limitations under the License. .\" .\" Author: Rob Crittenden .\" .TH "gencert" "8" "Jul 1 2013" "Rob Crittenden" "" .SH "NAME" gencert \- Generate a test NSS database for mod_nss .SH "SYNOPSIS" gencert .SH "DESCRIPTION" A tool used to generate a self\-signed CA as well as server and user certificates for mod_nss testing. .PP This is used to generate a default NSS database for the mod_nss Apache module. It does not test to see if an existing database already exists, so use with care. .PP \fBgencert\fP will generate a new NSS database with the password "httptest". .PP It generates a self\-signed CA with the subject "CN=Certificate Shack, O=example.com, C=US" .PP It also generates a certificate suitable for servers with the subject "CN=, O=example.com, C=US", and a user certificate with the subject "E=alpha@, CN=Frank Alpha, UID=alpha, OU=People, O=example.com, C=US". .PP The nicknames it uses are: .IP .TS tab(;); ll,ll. CA:;cacert Server certificate:;Server\-Cert User cert:;alpha .TE .SH OPTIONS .TP .B Specifies the destination directory where the NSS databases will be created. .SH BUGS Report bugs to http://bugzilla.redhat.com. .SH AUTHORS Rob Crittenden . .SH COPYRIGHT Copyright (c) 2011 Red Hat, Inc. This is licensed under the Apache License, Version 2.0 (the "License"); no one may use this file except in compliance with the License. A copy of this license is available at http://www.apache.org/licenses/LICENSE-2.0. .PP Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mod_nss-1.0.12/gencert.in000077500000000000000000000206171260357105600152320ustar00rootroot00000000000000#!/bin/bash # Copyright 2001-2004 The Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # $Header$ # # gencert - generate new CA, server and user certificates for NSS testing. # CERTUTIL=/usr/bin/certutil # Note: In order for the client tests that ship with this module to work # properly with this test certificate you need to ensure that the domain of # the server is the same as your domain. Otherwise you will get an error message # like -12776 (requested domain name does not match the server's certificate). getFQDN() { max=0 maxhost= OS=`uname -s` if [ $OS == "SunOS" ]; then if [ -x /usr/lib/mail/sh/check-hostname ]; then maxhost=`/usr/lib/mail/sh/check-hostname | awk 'BEGIN { FS=" " } { if ($3 == "OK:") { print $7 } }'` fi echo $maxhost return fi defhost=`hostname` hosthost=`host $defhost | grep -v "not found" | awk '{print $1}'` for host in $defhost $hosthost `hostname -f` `hostname -a` ; do len=`echo $host | wc -c` if [ $len -gt $max ]; then max=$len maxhost=$host fi done echo $maxhost } FQDN=`getFQDN` if [ "x${FQDN}" = "x" ]; then FQDN=localhost.localdomain fi CA_CERTDN="CN=Certificate Shack, O=example.com, C=US" SERVER_CERTDN="CN=${FQDN}, O=example.com, C=US" ALPHA_CERTDN="E=alpha@${FQDN}, CN=Frank Alpha, UID=alpha, OU=People, O=example.com, C=US" BETA_CERTDN="E=beta@${FQDN}, CN=Anna Beta, UID=beta, OU=People, O=example.com, C=US" # size of the keys KEYSIZE=2048 # validity of the certs in months VALIDITY=48 # starting point of serial numbers. 1 is the CA, 2 is the client cert "alpha" # 3 is the server cert "Server-Cert". CERTSERIAL=0 if [ $# -lt 1 ] then echo "usage: $0 " 1>&2 exit 1 fi PREFIX=`echo $1 | cut -d: -f1` DEST=`echo $1 | cut -d: -f2` if [ ! -d $DEST -o ! -w $DEST ] then echo "ERROR: $1 must be writable directory." 1>&2 exit 1 fi DBDIR=$1 shift if [ $# > 0 ]; then SNI=$1 else SNI=0 fi echo "httptest" > $DEST/pw.txt function generate_server_sni_cert { hostname=$1 local SERVER_DN="CN=${hostname}, O=SNI, O=example.com, C=US" local NICKNAME="Server-Cert-${hostname}" echo "" echo "#####################################################################" echo "Generating $NICKNAME server certificate request" echo "#####################################################################" (ps -elf; date; netstat -a) > $DEST/noise $CERTUTIL -R -d $DBDIR \ -s "$SERVER_DN" \ -o $DEST/tmpcertreq \ -g $KEYSIZE \ -z $DEST/noise \ -f $DEST/pw.txt echo "" echo "#####################################################################" echo "Generating $NICKNAME server certificate" echo "#####################################################################" let CERTSERIAL=CERTSERIAL+1 echo -e "2\n9\nn\n1\n9\nn\n" | \ $CERTUTIL -C -d $DBDIR \ -c cacert \ -i $DEST/tmpcertreq \ -o $DEST/tmpcert.der \ -m $CERTSERIAL \ -v $VALIDITY \ -f $DEST/pw.txt \ -1 \ -5 \ -8 $hostname rm $DEST/tmpcertreq echo "" echo "#####################################################################" echo "Importing $NICKNAME certificate into server cert DB" echo "#####################################################################" $CERTUTIL -A -d $DBDIR -n $NICKNAME \ -t u,u,u \ -i $DEST/tmpcert.der \ -f $DEST/pw.txt rm $DEST/tmpcert.der } echo "" echo "#####################################################################" echo "Generating new server certificate and key database. The password" echo "is httptest" echo "#####################################################################" $CERTUTIL -N -d $DBDIR -f $DEST/pw.txt echo "" echo "#####################################################################" echo "Generating self-signed client CA certificate" echo "#####################################################################" (ps -elf; date; netstat -a) > $DEST/noise let CERTSERIAL=CERTSERIAL+1 # 5 9 n -> Cert signing key # y 10 y -> basic constraints: CA cert # 5 6 7 9 n -> SSL, S/MIME, Object signing CA echo -e "5\n9\nn\ny\n10\ny\n5\n6\n7\n9\nn\n" | \ $CERTUTIL -S -d $DBDIR -n cacert \ -s "$CA_CERTDN" \ -x \ -t CTu,CTu,CTu \ -g $KEYSIZE \ -m $CERTSERIAL \ -v $VALIDITY \ -f $DEST/pw.txt \ -z $DEST/noise \ -2 \ -1 \ echo "" echo "#####################################################################" echo "Generating user certificate for \"alpha\"." echo "#####################################################################" (ps -elf; date; netstat -a) > $DEST/noise let CERTSERIAL=CERTSERIAL+1 # 0 2 9 n -> Key usage: Key Encipherment, Digital Signature # 0 9 n -> SSL Client echo -e "0\n2\n9\nn\n0\n9\nn\n" | \ $CERTUTIL -S -d $DBDIR -n alpha \ -s "$ALPHA_CERTDN" \ -c cacert \ -t u,pu,u \ -g $KEYSIZE \ -m $CERTSERIAL \ -v $VALIDITY \ -f $DEST/pw.txt \ -z $DEST/noise \ -1 \ -5 echo "" echo "#####################################################################" echo "Generating user certificate for \"beta\"." echo "#####################################################################" (ps -elf; date; netstat -a) > $DEST/noise let CERTSERIAL=CERTSERIAL+1 # 0 2 9 n -> Key usage: Key Encipherment, Digital Signature # 0 9 n -> SSL Client echo -e "0\n2\n9\nn\n0\n9\nn\n" | \ $CERTUTIL -S -d $DBDIR -n beta \ -s "$BETA_CERTDN" \ -c cacert \ -t u,pu,u \ -g $KEYSIZE \ -m $CERTSERIAL \ -v $VALIDITY \ -f $DEST/pw.txt \ -z $DEST/noise \ -1 \ -5 echo "" echo "#####################################################################" echo "Generating server certificate request" echo "#####################################################################" (ps -elf; date; netstat -a) > $DEST/noise $CERTUTIL -R -d $DBDIR \ -s "$SERVER_CERTDN" \ -o $DEST/tmpcertreq \ -g $KEYSIZE \ -z $DEST/noise \ -f $DEST/pw.txt echo "" echo "#####################################################################" echo "Generating server certificate" echo "#####################################################################" let CERTSERIAL=CERTSERIAL+1 echo -e "2\n9\nn\n1\n9\nn\n" | \ $CERTUTIL -C -d $DBDIR \ -c cacert \ -i $DEST/tmpcertreq \ -o $DEST/tmpcert.der \ -m $CERTSERIAL \ -v $VALIDITY \ -f $DEST/pw.txt \ -1 \ -5 \ -8 $FQDN rm $DEST/tmpcertreq echo "" echo "#####################################################################" echo "Importing server certificate into server cert DB" echo "#####################################################################" $CERTUTIL -A -d $DBDIR -n Server-Cert \ -t u,u,u \ -i $DEST/tmpcert.der \ -f $DEST/pw.txt rm $DEST/tmpcert.der if [ $SNI > 0 ]; then SNI=`expr $SNI + 1` count=1 while test $count -lt $SNI ; do generate_server_sni_cert www$count.example.com count=`expr $count + 1` done fi echo "" echo "#####################################################################" echo "Cleaning up" echo "#####################################################################" rm $DEST/pw.txt rm $DEST/noise echo "" echo "The database password is httptest" echo "" exit 0 mod_nss-1.0.12/makerpm.sh000077500000000000000000000035421260357105600152410ustar00rootroot00000000000000#!/bin/sh -xv # This script provides an example of how to build the various flavors # of the mod_nss rpm. If you don't have a source tarball, you # can create one from checking out the source tree (which you presumably # have if you have checked out this script) and putting it in # SOURCES/mod_nss-1.0.tar.gz. The things you need to define below # are: # RPM_PLATFORM - one of RHEL3, RHEL4, FC3, FC4, etc. - should correspond # to our internal build platform naming convention # FLAVOR - use dbg for debug builds and opt for optimized builds # NSPRDIR - directory holding NSPR include and lib directories # NSSDIR - directory holding NSS include and lib directories mkdirs() { for d in "$@" ; do if [ -d $d ]; then mv $d $d.deleted rm -rf $d.deleted & fi mkdir -p $d done } mkdirs SOURCES BUILD SRPMS RPMS cd SOURCES cvs -d $FEDCVSROOT co -d mod_nss-1.0 mod_nss tar cf - mod_nss-1.0 | gzip > mod_nss-1.0.tar.gz rm -rf mod_nss-1.0 cd .. # define PLATFORM to be RHEL3, RHEL4, FC3, FC4, etc. RPM_PLATFORM=RHEL4 # define FLAVOR to be dbg or opt for debug or optimized build FLAVOR=dbg # root dir for RPM built and temp files ABS_TOPDIR=`pwd` arch=`uname -i` #mkdirs RPMS/$arch # now define the locations of our components NSPRDIR=/share/builds/components/nspr/v4.4.1/RHEL4_x86_gcc3_DBG.OBJ NSSDIR=/share/builds/components/nss/NSS_3_9_3_RTM/RHEL4_x86_gcc3_DBG.OBJ rpmbuild --define "_topdir $ABS_TOPDIR" --define "_sourcedir $ABS_TOPDIR/SOURCES" --define "_rpmdir $ABS_TOPDIR/RPMS" --define "_srcrpmdir $ABS_TOPDIR/SRPMS" --define "ARCH $arch" --define "flavor $FLAVOR" --define "platform $RPM_PLATFORM" --define "nsprincdir $NSPRDIR/include" --define "nsprlibdir $NSPRDIR/lib" --define "nssincdir $NSSDIR/include" --define "nsslibdir $NSSDIR/lib" --nodeps -ba mod_nss.spec mod_nss-1.0.12/migrate.pl000077500000000000000000000245741260357105600152460ustar00rootroot00000000000000#!/usr/bin/perl # # Migrate configuration from OpenSSL to NSS use Cwd; use Getopt::Std; BEGIN { $NSSDir = cwd(); $SSLCACertificatePath = ""; $SSLCACertificateFile = ""; $SSLCertificateFile = ""; $SSLCARevocationPath = ""; $SSLCARevocationFile = ""; $SSLCertificateKeyFile = ""; $passphrase = 0; } %skip = ( "SSLRandomSeed" => "", "SSLSessionCache" => "", "SSLMutex" => "", "SSLCertificateChainFile" => "", "SSLVerifyDepth" => "" , "SSLCryptoDevice" => "" , "LoadModule" => "" , ); %insert = ( "NSSSessionCacheTimeout", "NSSSessionCacheSize 10000\nNSSSession3CacheTimeout 86400\n",); getopts('ch'); if ($opt_h) { print "Usage: migrate.pl -c\n"; print "\t-c convert the certificates\n"; exit(); } open (NSS, "> nss.conf") or die "Unable to open nss.conf: $!.\n"; open (SSL, "< ssl.conf") or die "Unable to open ssl.conf: $!.\n"; while () { my $comment = 0; # skip blank lines and comments if (/^#/ || /^\s*$/) { print NSS $_; next; } m/(\w+)\s+(.+)/; $stmt = $1; $value = $2; # Handle the special cases if ($stmt eq "SSLVerifyClient" && $value eq "optional_no_ca") { print NSS "# Replaced optional_no_ca with optional\n"; print NSS "SSLVerifyClient optional\n"; next; } if ($stmt eq "SSLCipherSuite") { print NSS "NSSCipherSuite ", get_ciphers($val), "\n"; print NSS "NSSProtocol SSLv3,TLSv1\n"; $comment = 1; } elsif ($stmt eq "SSLCACertificatePath") { $SSLCACertificatePath = $value; $comment = 1; } elsif ($stmt eq "SSLCACertificateFile") { $SSLCACertificateFile = $value; $comment = 1; } elsif ($stmt eq "SSLCertificateFile") { print NSS "NSSCertificateDatabase $NSSDir\n"; print NSS "NSSNickName Server-Cert\n"; $SSLCertificateFile = $value; $comment = 1; } elsif ($stmt eq "SSLCertificateKeyFile") { $SSLCertificateKeyFile = $value; $comment = 1; } elsif ($stmt eq "SSLCARevocationPath") { $SSLCARevocationPath = $value; $comment = 1; } elsif ($stmt eq "SSLCARevocationFile") { $SSLCARevocationFile = $value; $comment = 1; } elsif ($stmt eq "SSLPassPhraseDialog") { print NSS "NSSPassPhraseHelper /usr/local/bin/nss_pcache\n"; $passphrase = 1; $comment = 1; } if (exists($skip{$stmt})) { print NSS "# Skipping, not applicable in mod_nss\n"; print NSS "##$_"; next; } # Fix up any remaining directive names s/^SSL/NSS/; if (exists($insert{$stmt})) { print NSS "$_"; print NSS $insert{$stmt}; next; } # Fall-through to print whatever is left if ($comment) { print NSS "##$_"; $comment = 0; } else { print NSS $_; } } if ($passphrase == 0) { # NOTE: Located at '/usr/sbin/nss_pcache' prior to 'mod_nss-1.0.9'. print NSS "NSSPassPhraseHelper /usr/libexec/nss_pcache\n"; } close(NSS); close(SSL); # # Create NSS certificate database and import any existing certificates # if ($opt_c) { print "Creating NSS certificate database.\n"; run_command("certutil -N -d $NSSDir"); # Convert the certificate into pkcs12 format if ($SSLCertificateFile ne "" && $SSLCertificateKeyFile ne "") { my $subject = get_cert_subject($SSLCertificateFile); print "Importing certificate $subject as \"Server-Cert\".\n"; run_command("openssl pkcs12 -export -in $SSLCertificateFile -inkey $SSLCertificateKeyFile -out server.p12 -name \"Server-Cert\" -passout pass:foo"); run_command("pk12util -i server.p12 -d $NSSDir -W foo"); } if ($SSLCACertificateFile ne "") { my $subject = get_cert_subject($SSLCACertificateFile); if ($subject ne "") { print "Importing CA certificate $subject\n"; run_command("certutil -A -n \"$subject\" -t \"CT,,\" -d $NSSDir -a -i $SSLCACertificateFile"); } } if ($SSLCACertificatePath ne "") { opendir(DIR, $SSLCACertificatePath) or die "can't opendir $SSLCACertificatePath: $!"; while (defined($file = readdir(DIR))) { next if -d $file; # we can operate directly on the hash files so don't have to worry # about any SKIPME's. if ($file =~ /hash.*/) { my $subject = get_cert_subject("$SSLCACertificatePath/$file"); if ($subject ne "") { print "Importing CA certificate $subject\n"; run_command("certutil -A -n \"$subject\" -t \"CT,,\" -d $NSSDir -a -i $SSLCACertificatePath/$file"); } } } closedir(DIR); } if ($SSLCARevocationFile ne "") { print "Importing CRL file $CARevocationFile\n"; # Convert to DER format run_command("openssl crl -in $SSLCARevocationFile -out /tmp/crl.tmp -inform PEM -outform DER"); run_command("crlutil -I -t 1 -d $NSSDir -i /tmp/crl.tmp"); unlink("/tmp/crl.tmp"); } if ($SSLCARevocationPath ne "") { opendir(DIR, $SSLCARevocationPath) or die "can't opendir $SSLCARevocationPath: $!"; while (defined($file = readdir(DIR))) { next if -d $file; # we can operate directly on the hash files so don't have to worry # about any SKIPME's. if ($file =~ /hash.*/) { my $subject = get_cert_subject("$SSLCARevocationPath/$file"); if ($subject ne "") { print "Importing CRL file $file\n"; # Convert to DER format run_command("openssl crl -in $SSLCARevocationPath/$file -out /tmp/crl.tmp -inform PEM -outform DER"); run_command("crlutil -I -t 1 -d $NSSDir -i /tmp/crl.tmp"); unlink("/tmp/crl.tmp"); } } } closedir(DIR); } } print "Conversion complete.\n"; print "You will need to:\n"; print " - rename/remove ssl.conf or Apache will not start.\n"; print " - verify the location of nss_pcache. It is set as /usr/local/bin/nss_pcache\n"; exit(0); # Migrate configuration from OpenSSL to NSS sub get_ciphers { my $str = shift; %cipher_list = ( "rc4" => ":ALL:SSLv2:RSA:MD5:MEDIUM:RC4:", "rc4export" => ":ALL:SSLv2:RSA:EXP:EXPORT40:MD5:RC4:", "rc2" => ":ALL:SSLv2:RSA:MD5:MEDIUM:RC2:", "rc2export" => ":ALL:SSLv2:RSA:EXP:EXPORT40:MD5:RC2:", "des" => ":ALL:SSLv2:RSA:EXP:EXPORT56:MD5:DES:LOW:", "desede3" => ":ALL:SSLv2:RSA:MD5:3DES:HIGH:", "rsa_rc4_128_md5" => ":ALL:SSLv3:TLSv1:RSA:MD5:RC4:MEDIUM:", "rsa_rc4_128_sha" => ":ALL:SSLv3:TLSv1:RSA:SHA:RC4:MEDIUM:", "rsa_3des_sha" => ":ALL:SSLv3:TLSv1:RSA:SHA:3DES:HIGH:", "rsa_des_sha" => ":ALL:SSLv3:TLSv1:RSA:SHA:DES:LOW:", "rsa_rc4_40_md5" => ":ALL:SSLv3:TLSv1:RSA:EXP:EXPORT40:RC4:", "rsa_rc2_40_md5" => ":ALL:SSLv3:TLSv1:RSA:EXP:EXPORT40:RC2:", "rsa_null_md5" => ":SSLv3:TLSv1:RSA:MD5:NULL:", "rsa_null_sha" => ":SSLv3:TLSv1:RSA:SHA:NULL:", "rsa_des_56_sha" => ":ALL:SSLv3:TLSv1:RSA:DES:SHA:EXP:EXPORT56:", "rsa_rc4_56_sha" => ":ALL:SSLv3:TLSv1:RSA:RC4:SHA:EXP:EXPORT56:", ); $NUM_CIPHERS = 16; for ($i = 0; $i < $NUM_CIPHERS; $i++) { $selected[$i] = 0; } # Don't need to worry about the ordering properties of "+" because # NSS always chooses the "best" cipher anyway. You can't specify # preferred order. # -1: this cipher is completely out # 0: this cipher is currently unselected, but maybe added later # 1: this cipher is selected @s = split(/:/, $str); for ($i = 0; $i <= $#s; $i++) { $j = 0; $val = 1; # ! means this cipher is disabled forever if ($s[$i] =~ /^!/) { $val = -1; ($s[$i] =~ s/^!//); } elsif ($s[$i] =~ /^-/) { $val = 0; ($s[$i] =~ s/^-//); } elsif ($s[$i] =~ /^+/) { ($s[$i] =~ s/^+//); } for $cipher (sort keys %cipher_list) { $match = 0; # For embedded + we do an AND for all options if ($s[$i] =~ m/(\w+\+)+/) { @sub = split(/^\+/, $s[$i]); $match = 1; for ($k = 0; $k <=$#sub; $k++) { if ($cipher_list{$cipher} !=~ m/:$sub[$k]:/) { $match = 0; } } } else { # straightforward match if ($cipher_list{$cipher} =~ m/:$s[$i]:/) { $match = 1; } } if ($match && $selected[$j] != -1) { $selected[$j] = $val; } $j++; } } # NSS doesn't honor the order of a cipher list, it uses the "strongest" # cipher available. So we'll print out the ciphers as SSLv2, SSLv3 and # the NSS ciphers not available in OpenSSL. $str = "SSLv2:SSLv3"; @s = split(/:/, $str); $ciphersuite = ""; for ($i = 0; $i <= $#s; $i++) { $j = 0; for $cipher (sort keys %cipher_list) { if ($cipher_list{$cipher} =~ m/:$s[$i]:/) { if ($selected[$j]) { $ciphersuite .= "+"; } else { $ciphersuite .= "-"; } $ciphersuite .= $cipher . ","; } $j++; } } $ciphersuite .= "-fortezza,-fortezza_rc4_128_sha,-fortezza_null,-fips_des_sha,+fips_3des_sha,-rsa_aes_128_sha,-rsa_aes_256_sha"; return $ciphersuite; } # Given the filename of a PEM file, use openssl to fetch the certificate # subject sub get_cert_subject { my $file = shift; my $subject = ""; return "" if ! -T $file; $subject = `openssl x509 -subject < $file | head -1`; $subject =~ s/subject= \///; # Remove leading subject= \ $subject =~ s/\//,/g; # Replace / with , as separator $subject =~ s/Email=.*(,){0,1}//; # Remove Email attribute $subject =~ s/,$//; # Remove any trailing commas chomp($subject); return $subject; } # # Wrapper around the system() command sub run_command { my @args = shift; my $status = 0; $status = 0xffff & system(@args); return if ($status == 0); print "Command '@args' failed: $!\n"; exit; } mod_nss-1.0.12/mod_nss.c000066400000000000000000000423141260357105600150540ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" #include #include "sslerr.h" /* * the table of configuration directives we provide */ #define SSL_CMD_ALL(name, args, desc) \ AP_INIT_##args("NSS"#name, nss_cmd_NSS##name, \ NULL, RSRC_CONF|OR_AUTHCFG, desc), #define SSL_CMD_SRV(name, args, desc) \ AP_INIT_##args("NSS"#name, nss_cmd_NSS##name, \ NULL, RSRC_CONF, desc), #define SSL_CMD_DIR(name, type, args, desc) \ AP_INIT_##args("NSS"#name, nss_cmd_NSS##name, \ NULL, OR_##type, desc), #define AP_END_CMD { NULL } static const command_rec nss_config_cmds[] = { /* * Global (main-server) context configuration directives */ SSL_CMD_SRV(CertificateDatabase, TAKE1, "SSL Server Certificate database " "(`/path/to/file'") SSL_CMD_SRV(DBPrefix, TAKE1, "NSS Database prefix (optional) " "(`my-prefix-'") SSL_CMD_SRV(SessionCacheTimeout, TAKE1, "SSL 2 Session Cache object lifetime " "(`N' - number of seconds)") SSL_CMD_SRV(Session3CacheTimeout, TAKE1, "SSL 3/TLS Session Cache object lifetime " "(`N' - number of seconds)") SSL_CMD_SRV(SessionCacheSize, TAKE1, "SSL Session Cache size " "(`N' - number of entries)") SSL_CMD_SRV(PassPhraseDialog, TAKE1, "SSL dialog mechanism for the pass phrase query " "(`builtin', `file:/path/to/file`") SSL_CMD_SRV(PassPhraseHelper, TAKE1, "Process to securely store SSL tokens to handle restarts " "(`/path/to/file`") SSL_CMD_SRV(OCSP, FLAG, "OCSP (Online Certificate Status Protocol)" "(`on', `off')") SSL_CMD_SRV(OCSPDefaultResponder, FLAG, "Use a default OCSP Responder" "(`on', `off')") SSL_CMD_SRV(OCSPDefaultURL, TAKE1, "The URL of the OCSP default responder" "(`http://example.com:80/ocsp") SSL_CMD_SRV(OCSPDefaultName, TAKE1, "The nickname of the certificate to trust to sign the OCSP responses." "(`OCSP_Cert`") SSL_CMD_SRV(RandomSeed, TAKE23, "SSL Pseudo Random Number Generator (PRNG) seeding source " "(`startup builtin|file:/path|exec:/path [bytes]')") /* * Per-server context configuration directives */ SSL_CMD_SRV(Engine, FLAG, "SSL switch for the protocol engine " "(`on', `off')") SSL_CMD_SRV(FIPS, FLAG, "FIPS 140-1 mode " "(`on', `off')") SSL_CMD_SRV(SNI, FLAG, "SNI" "(`on', `off')") SSL_CMD_SRV(StrictSNIVHostCheck, FLAG, "Strict SNI virtual host checking") SSL_CMD_ALL(CipherSuite, TAKE1, "Comma-delimited list of permitted SSL Ciphers, + to enable, - to disable " "(`[+-]XXX,...,[+-]XXX' - see manual)") SSL_CMD_SRV(Protocol, RAW_ARGS, "Enable the various SSL protocols" "(`[SSLv2|SSLv3|TLSv1.0|TLSv1.1|TLSv1.2|all] ...' - see manual)") SSL_CMD_ALL(VerifyClient, TAKE1, "SSL Client Authentication " "(`none', `optional', `require'") SSL_CMD_SRV(Nickname, TAKE1, "SSL RSA Server Certificate nickname " "(`Server-Cert'") #ifdef SSL_ENABLE_RENEGOTIATION SSL_CMD_SRV(Renegotiation, FLAG, "Enable SSL Renegotiation (default off) " "(`on', `off')") SSL_CMD_SRV(RequireSafeNegotiation, FLAG, "If Rengotiation is allowed, require safe negotiation (default off) " "(`on', `off')") #endif #ifdef NSS_ENABLE_ECC SSL_CMD_SRV(ECCNickname, TAKE1, "SSL ECC Server Certificate nickname " "(`Server-Cert'") #endif SSL_CMD_SRV(EnforceValidCerts, FLAG, "Require a valid, trust, non-expired server certificate (default on)" "(`on', `off'") SSL_CMD_SRV(SessionTickets, FLAG, "Enable or disable TLS session tickets" "(`on', `off')") SSL_CMD_ALL(UserName, TAKE1, "Set user name to SSL variable value") /* * Per-directory context configuration directives */ SSL_CMD_DIR(Options, OPTIONS, RAW_ARGS, "Set one or more options to configure the SSL engine" "(`[+-]option[=value] ...' - see manual)") SSL_CMD_DIR(RequireSSL, AUTHCFG, NO_ARGS, "Require the SSL protocol for the per-directory context " "(no arguments)") SSL_CMD_DIR(Require, AUTHCFG, RAW_ARGS, "Require a boolean expression to evaluate to true for granting access" "(arbitrary complex boolean expression - see manual)") SSL_CMD_DIR(RenegBufferSize, AUTHCFG, TAKE1, "Configure the amount of memory that will be used for buffering the " "request body if a per-location SSL renegotiation is required due to " "changed access control requirements") /* * Proxy configuration for remote SSL connections */ SSL_CMD_SRV(ProxyEngine, FLAG, "SSL switch for the proxy protocol engine " "(`on', `off')") SSL_CMD_SRV(ProxyProtocol, RAW_ARGS, "SSL Proxy: enable or disable SSL protocol flavors " "(`[+-][SSLv2|SSLv3|TLSv1.0|TLSv1.1|TLSv1.2] ...' - see manual)") SSL_CMD_SRV(ProxyCipherSuite, TAKE1, "SSL Proxy: colon-delimited list of permitted SSL ciphers " "(`XXX:...:XXX' - see manual)") SSL_CMD_SRV(ProxyNickname, TAKE1, "SSL Proxy: client certificate Nickname to be for proxy connections " "(`nickname')") SSL_CMD_SRV(ProxyCheckPeerCN, FLAG, "SSL Proxy: check the peers certificate CN") #ifdef IGNORE /* Deprecated directives. */ AP_INIT_RAW_ARGS("NSSLog", ap_set_deprecated, NULL, OR_ALL, "SSLLog directive is no longer supported - use ErrorLog."), AP_INIT_RAW_ARGS("NSSLogLevel", ap_set_deprecated, NULL, OR_ALL, "SSLLogLevel directive is no longer supported - use LogLevel."), #endif AP_INIT_TAKE1("User", set_user, NULL, RSRC_CONF, "Apache user. Comes from httpd.conf."), AP_END_CMD }; /* * the various processing hooks */ static int nss_hook_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { /* Register us to handle mod_log_config %c/%x variables */ nss_var_log_config_register(pconf); return OK; } static SSLConnRec *nss_init_connection_ctx(conn_rec *c) { SSLConnRec *sslconn = myConnConfig(c); if (sslconn) { return sslconn; } sslconn = apr_pcalloc(c->pool, sizeof(*sslconn)); sslconn->is_proxy = 0; sslconn->disabled = 0; sslconn->non_nss_request = 0; sslconn->ssl = NULL; myConnConfigSet(c, sslconn); return sslconn; } static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *othermod_proxy_enable; static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *othermod_engine_disable; int nss_proxy_enable(conn_rec *c) { SSLSrvConfigRec *sc = mySrvConfig(c->base_server); SSLConnRec *sslconn = nss_init_connection_ctx(c); if (!sc->proxy_enabled) { if (othermod_proxy_enable) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "mod_nss proxy not configured, passing through to mod_ssl module"); return othermod_proxy_enable(c); } ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, "SSL Proxy requested for %s but not enabled " "[Hint: NSSProxyEngine]", sc->vhost_id); return 0; } sslconn->is_proxy = 1; sslconn->disabled = 0; return 1; } static int ssl_proxy_enable(conn_rec *c) { return nss_proxy_enable(c); } int nss_engine_disable(conn_rec *c) { SSLSrvConfigRec *sc = mySrvConfig(c->base_server); SSLConnRec *sslconn; if (othermod_engine_disable) { othermod_engine_disable(c); } if (sc->enabled == FALSE) { return 0; } sslconn = nss_init_connection_ctx(c); sslconn->disabled = 1; return 1; } static int ssl_engine_disable(conn_rec *c) { return nss_engine_disable(c); } /* Callback for an incoming certificate that is not valid */ SECStatus NSSBadCertHandler(void *arg, PRFileDesc * socket) { conn_rec *c = (conn_rec *)arg; SSLSrvConfigRec *sc = mySrvConfig(c->base_server); PRErrorCode err = PR_GetError(); SECStatus rv = SECFailure; CERTCertificate *peerCert = SSL_PeerCertificate(socket); const char *hostname_note; switch (err) { case SSL_ERROR_BAD_CERT_DOMAIN: if (sc->proxy_ssl_check_peer_cn == TRUE) { if ((hostname_note = apr_table_get(c->notes, "proxy-request-hostname")) != NULL) { apr_table_unset(c->notes, "proxy-request-hostname"); rv = CERT_VerifyCertName(peerCert, hostname_note); if (rv != SECSuccess) { char *remote = CERT_GetCommonName(&peerCert->subject); ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "SSL Proxy: Possible man-in-the-middle attack. The remote server is %s, we expected %s", remote, hostname_note); PORT_Free(remote); } } else { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "SSL Proxy: I don't have the name of the host we're supposed to connect to so I can't verify that we are connecting to who we think we should be. Giving up."); } } else { rv = SECSuccess; } break; default: ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Bad remote server certificate: %d", err); nss_log_nss_error(APLOG_MARK, APLOG_ERR, NULL); break; } return rv; } /* Callback to pull the client certificate upon server request */ static SECStatus NSSGetClientAuthData(void *arg, PRFileDesc *socket, CERTDistNames *caNames, CERTCertificate **pRetCert,/*return */ SECKEYPrivateKey **pRetKey) { CERTCertificate * cert; SECKEYPrivateKey * privKey; void * proto_win = NULL; SECStatus rv = SECFailure; char * localNickName = (char *)arg; proto_win = SSL_RevealPinArg(socket); if (localNickName) { cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), localNickName, certUsageSSLClient, PR_FALSE, proto_win); if (cert) { privKey = PK11_FindKeyByAnyCert(cert, proto_win); if (privKey) { rv = SECSuccess; } else { CERT_DestroyCertificate(cert); } } if (rv == SECSuccess) { *pRetCert = cert; *pRetKey = privKey; } } return rv; } static int nss_hook_pre_connection(conn_rec *c, void *csd) { SSLSrvConfigRec *sc = mySrvConfig(c->base_server); PRFileDesc *ssl; SSLConnRec *sslconn = myConnConfig(c); modnss_ctx_t *mctx; /* * Immediately stop processing if SSL is disabled for this connection */ if (!(sc && (sc->enabled || (sslconn && sslconn->is_proxy)))) { return DECLINED; } /* * Create SSL context */ if (!sslconn) { sslconn = nss_init_connection_ctx(c); } if (sslconn->disabled) { return DECLINED; } /* * Remember the connection information for * later access inside callback functions */ ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "Connection to child %ld established " "(server %s, client %s)", c->id, sc->vhost_id, #if AP_SERVER_MINORVERSION_NUMBER <= 2 c->remote_ip ? c->remote_ip : "unknown"); #else c->client_ip ? c->client_ip : "unknown"); #endif mctx = sslconn->is_proxy ? sc->proxy : sc->server; /* * Create a new SSL connection with the configured server SSL context and * attach this to the socket. Additionally we register this attachment * so we can detach later. */ ssl = nss_io_new_fd(); ssl = SSL_ImportFD(mctx->model, ssl); if (!(ssl)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, "Unable to create a new SSL connection from the SSL " "context"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, c->base_server); c->aborted = 1; return DECLINED; /* XXX */ } sslconn->ssl = ssl; sslconn->client_socket = csd; nss_io_filter_init(c, ssl); SSL_ResetHandshake(ssl, mctx->as_server); /* If we are doing a client connection, set our own bad certificate * handler and register the nickname we want to use in case client * authentication is requested. */ if (!mctx->as_server) { if (SSL_BadCertHook(ssl, (SSLBadCertHandler) NSSBadCertHandler, c) != SECSuccess) { /* errors are reported in the certificate handler */ return DECLINED; } if (mctx->nickname) { if (SSL_GetClientAuthDataHook(ssl, NSSGetClientAuthData, (void*)mctx->nickname) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, "Unable to register client authentication callback"); return DECLINED; } } } return APR_SUCCESS; } static const char *nss_hook_http_scheme(const request_rec *r) { SSLSrvConfigRec *sc = mySrvConfig(r->server); if (sc->enabled == FALSE) { return NULL; } return "https"; } static apr_port_t nss_hook_default_port(const request_rec *r) { SSLSrvConfigRec *sc = mySrvConfig(r->server); if (sc->enabled == FALSE) { return 0; } return 443; } /* * the module registration phase */ static void nss_register_hooks(apr_pool_t *p) { /* nss_hook_ReadReq needs to use the BrowserMatch settings so must * run after mod_setenvif's post_read_request hook. */ static const char *pre_prr[] = { "mod_setenvif.c", NULL }; nss_io_filter_register(p); ap_hook_pre_connection(nss_hook_pre_connection,NULL,NULL, APR_HOOK_MIDDLE); ap_hook_post_config (nss_init_Module, NULL,NULL, APR_HOOK_MIDDLE); #if AP_SERVER_MINORVERSION_NUMBER < 2 /* See comment in mod_nss.h */ ap_hook_http_method (nss_hook_http_scheme, NULL,NULL, APR_HOOK_MIDDLE); #else ap_hook_http_scheme (nss_hook_http_scheme, NULL,NULL, APR_HOOK_MIDDLE); #endif ap_hook_default_port (nss_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_pre_config (nss_hook_pre_config, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_child_init (nss_init_Child, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_check_user_id (nss_hook_UserCheck, NULL,NULL, APR_HOOK_FIRST); ap_hook_fixups (nss_hook_Fixup, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_access_checker(nss_hook_Access, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_auth_checker (nss_hook_Auth, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_post_read_request(nss_hook_ReadReq, pre_prr,NULL, APR_HOOK_MIDDLE); nss_var_register(); /* Always register these mod_nss optional functions */ APR_REGISTER_OPTIONAL_FN(nss_proxy_enable); APR_REGISTER_OPTIONAL_FN(nss_engine_disable); /* Save the state of any previously registered mod_ssl functions */ othermod_proxy_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable); othermod_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); /* Always register these local mod_ssl optional functions */ APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); } module AP_MODULE_DECLARE_DATA nss_module = { STANDARD20_MODULE_STUFF, nss_config_perdir_create, /* create per-dir config structures */ nss_config_perdir_merge, /* merge per-dir config structures */ nss_config_server_create, /* create per-server config structures */ nss_config_server_merge, /* merge per-server config structures */ nss_config_cmds, /* table of configuration directives */ nss_register_hooks /* register hooks */ }; mod_nss-1.0.12/mod_nss.h000066400000000000000000000371021260357105600150600ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __MOD_NSS_H__ #define __MOD_NSS_H__ /* Apache headers */ #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_main.h" #include "http_connection.h" #include "http_request.h" #include "http_protocol.h" #include "mod_ssl.h" #include "util_script.h" #include "util_filter.h" #include "apr.h" #include "apr_strings.h" #define APR_WANT_STRFUNC #include "apr_want.h" #include "apr_tables.h" #include "apr_lib.h" #include "apr_fnmatch.h" #include "apr_strings.h" #include "apr_dbm.h" #include "apr_rmm.h" #include "apr_shm.h" #include "apr_global_mutex.h" #include "apr_optional.h" #include #include #include #define MOD_NSS_VERSION PACKAGE_VERSION /* NSPR headers */ #include "nspr.h" #include #include /* NSS header files */ #include #include #include #include /* Apache ships its autoconf-generated config.h which defines these * as empty. We want the mod_nss version in our own config.h so * undefine them to eliminate the build warnings. */ #undef PACKAGE_NAME #undef PACKAGE_VERSION #undef PACKAGE_STRING #undef PACKAGE_TARNAME #undef PACKAGE_URL #undef PACKAGE_BUGREPORT #include "config.h" /* The #ifdef macros are only defined AFTER including the above * therefore we cannot include these system files at the top :-( */ #if APR_HAVE_SYS_TIME_H #include #endif #if APR_HAVE_UNISTD_H #include /* needed for STDIN_FILENO et.al., at least on FreeBSD */ #endif /* mod_ssl headers */ #include "nss_expr.h" /* * Provide reasonable default for some defines */ #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (!FALSE) #endif #ifndef PFALSE #define PFALSE ((void *)FALSE) #endif #ifndef PTRUE #define PTRUE ((void *)TRUE) #endif #ifndef UNSET #define UNSET (-1) #endif #ifndef NUL #define NUL '\0' #endif /* * Provide reasonable defines for some types */ #ifndef BOOL #define BOOL unsigned int #endif #ifndef UCHAR #define UCHAR unsigned char #endif /* * Provide useful shorthands */ #define strEQ(s1,s2) (strcmp(s1,s2) == 0) #define strNE(s1,s2) (strcmp(s1,s2) != 0) #define strEQn(s1,s2,n) (strncmp(s1,s2,n) == 0) #define strNEn(s1,s2,n) (strncmp(s1,s2,n) != 0) #define strcEQ(s1,s2) (strcasecmp(s1,s2) == 0) #define strcNE(s1,s2) (strcasecmp(s1,s2) != 0) #define strcEQn(s1,s2,n) (strncasecmp(s1,s2,n) == 0) #define strcNEn(s1,s2,n) (strncasecmp(s1,s2,n) != 0) #define strIsEmpty(s) (s == NULL || s[0] == NUL) #define myConnConfig(c) \ (SSLConnRec *)ap_get_module_config(c->conn_config, &nss_module) #define myCtxConfig(sslconn, sc) (sslconn->is_proxy ? sc->proxy : sc->server) #define myConnConfigSet(c, val) \ ap_set_module_config(c->conn_config, &nss_module, val) #define mySrvConfig(srv) (SSLSrvConfigRec *)ap_get_module_config(srv->module_config, &nss_module) #define myDirConfig(req) (SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &nss_module) #define myModConfig(srv) (mySrvConfig((srv)))->mc /* * Defaults for the configuration */ #ifndef SSL_SESSION_CACHE_TIMEOUT #define SSL_SESSION_CACHE_TIMEOUT 100 #endif #ifndef SSL3_SESSION_CACHE_TIMEOUT #define SSL3_SESSION_CACHE_TIMEOUT 86400 #endif #ifndef SSL_SESSION_CACHE_SIZE #define SSL_SESSION_CACHE_SIZE 10000 #endif /* Default setting for per-dir reneg buffer. */ #ifndef DEFAULT_RENEG_BUFFER_SIZE #define DEFAULT_RENEG_BUFFER_SIZE (128 * 1024) #endif /* * Define the SSL options */ #define SSL_OPT_NONE (0) #define SSL_OPT_RELSET (1<<0) #define SSL_OPT_STDENVVARS (1<<1) #define SSL_OPT_COMPATENVVARS (1<<2) #define SSL_OPT_EXPORTCERTDATA (1<<3) #define SSL_OPT_FAKEBASICAUTH (1<<4) #define SSL_OPT_STRICTREQUIRE (1<<5) #define SSL_OPT_OPTRENEGOTIATE (1<<6) #define SSL_OPT_ALL (SSL_OPT_STDENVVARS|SSL_OPT_COMPATENVVAR|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE) typedef int nss_opt_t; /* * Define the SSL requirement structure */ typedef struct { char *cpExpr; nss_expr *mpExpr; } nss_require_t; /* * Define the SSL random number generator seeding source. The CONNECT * method is not currently used. */ typedef enum { SSL_RSCTX_STARTUP = 1, SSL_RSCTX_CONNECT = 2 } ssl_rsctx_t; typedef enum { SSL_RSSRC_BUILTIN = 1, SSL_RSSRC_FILE = 2, SSL_RSSRC_EXEC = 3 } ssl_rssrc_t; typedef struct { ssl_rsctx_t nCtx; ssl_rssrc_t nSrc; char *cpPath; int nBytes; } ssl_randseed_t; /* * Define the SSL verify levels */ typedef enum { SSL_CVERIFY_UNSET = UNSET, SSL_CVERIFY_NONE = 0, SSL_CVERIFY_OPTIONAL = 1, SSL_CVERIFY_REQUIRE = 2, SSL_CVERIFY_OPTIONAL_NO_CA = 3 } nss_verify_t; /* * Define the SSL pass phrase dialog types */ typedef enum { SSL_PPTYPE_UNSET = UNSET, SSL_PPTYPE_BUILTIN = 0, SSL_PPTYPE_FILE = 1, SSL_PPTYPE_DEFER = 2, } nss_pphrase_t; /* * Define the mod_ssl per-module configuration structure * (i.e. the global configuration for each httpd process) */ typedef struct { PRFileDesc *ssl; const char *client_dn; CERTCertificate *client_cert; int is_proxy; int disabled; int non_nss_request; apr_socket_t * client_socket; } SSLConnRec; typedef struct { pid_t pid; int nInitCount; apr_pool_t *pPool; apr_pool_t *ptemp; /* pointer to ptemp passed in during init */ const char *pCertificateDatabase; const char *pDBPrefix; /* config for SSL session cache */ int session_cache_size; int session_cache_timeout; int ssl3_session_cache_timeout; /* config for handling encrypted keys */ nss_pphrase_t pphrase_dialog_type; const char *pphrase_dialog_path; const char *pphrase_dialog_helper; apr_proc_t proc; apr_procattr_t *procattr; apr_array_header_t *aRandSeed; struct { void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10; } rCtx; int semid; const char *user; } SSLModConfigRec; typedef struct SSLSrvConfigRec SSLSrvConfigRec; /* stuff related to authentication that can also be per-dir */ typedef struct { const char *cipher_suite; const char *protocols; /* for client or downstream server authentication */ nss_verify_t verify_mode; } modnss_auth_ctx_t; typedef struct { SSLSrvConfigRec *sc; /* pointer back to server config */ char *cipherSuite; int as_server; int ssl3; int tls; int tlsrollback; int enforce; #ifdef SSL_ENABLE_RENEGOTIATION int enablerenegotiation; int requiresafenegotiation; #endif const char *nickname; #ifdef NSS_ENABLE_ECC const char *eccnickname; #endif CERTCertificate *servercert; SECKEYPrivateKey *serverkey; SSLKEAType serverKEAType; #ifdef NSS_ENABLE_ECC CERTCertificate *eccservercert; SECKEYPrivateKey *eccserverkey; SSLKEAType eccserverKEAType; #endif PRFileDesc *model; /* used to model an SSL socket */ modnss_auth_ctx_t auth; } modnss_ctx_t; struct SSLSrvConfigRec { SSLModConfigRec *mc; BOOL fips; BOOL ocsp_default; const char *ocsp_url; const char *ocsp_name; BOOL ocsp; BOOL enabled; BOOL sni; BOOL strict_sni_vhost_check; BOOL proxy_enabled; const char *vhost_id; int vhost_id_len; modnss_ctx_t *server; modnss_ctx_t *proxy; BOOL proxy_ssl_check_peer_cn; BOOL session_tickets; }; /* * Define the mod_ssl per-directory configuration structure * (i.e. the local configuration for all * and .htaccess contexts) */ typedef struct { BOOL bSSLRequired; apr_array_header_t *aRequirement; int nOptions; int nOptionsAdd; int nOptionsDel; const char *szCipherSuite; nss_verify_t nVerifyClient; const char *szUserName; apr_size_t nRenegBufferSize; } SSLDirConfigRec; /* * for cipher definitions see nss_engine_cipher.h */ /* pool and hash to store ServerName and NSSNickname pairs for SNI */ apr_pool_t *mp; apr_hash_t *ht; /* Compatibility between Apache 2.0.x and 2.2.x. The numeric version of * the version first appeared in Apache 2.0.56-dev. I picked 2.0.55 as it * is the last version without this define. This is used for more than just * the below defines. It also determines which API is used. */ #ifndef AP_SERVER_MAJORVERSION_NUMBER #define AP_SERVER_MAJORVERSION_NUMBER 2 #define AP_SERVER_MINORVERSION_NUMBER 0 #define AP_SERVER_PATCHLEVEL_NUMBER 55 #endif #if AP_SERVER_MINORVERSION_NUMBER < 2 typedef struct regex_t ap_regex_t; #define AP_REG_EXTENDED REG_EXTENDED #define AP_REG_NOSUB REG_NOSUB #define AP_REG_ICASE REG_ICASE #endif /* * function prototypes */ /* API glue structures */ extern module AP_MODULE_DECLARE_DATA nss_module; /* configuration handling */ SSLModConfigRec *nss_config_global_create(server_rec *); void *nss_config_perdir_create(apr_pool_t *p, char *dir); void *nss_config_perdir_merge(apr_pool_t *p, void *basev, void *addv); void *nss_config_server_create(apr_pool_t *p, server_rec *s); void *nss_config_server_merge(apr_pool_t *p, void *basev, void *addv); const char *nss_cmd_NSSFIPS(cmd_parms *, void *, int); const char *nss_cmd_NSSSNI(cmd_parms *, void *, int); const char *nss_cmd_NSSStrictSNIVHostCheck(cmd_parms *, void *, int); const char *nss_cmd_NSSEngine(cmd_parms *, void *, int); const char *nss_cmd_NSSOCSP(cmd_parms *, void *, int); const char *nss_cmd_NSSOCSPDefaultResponder(cmd_parms *, void *, int); const char *nss_cmd_NSSOCSPDefaultURL(cmd_parms *, void *dcfg, const char *arg); const char *nss_cmd_NSSOCSPDefaultName(cmd_parms *, void *, const char *arg); const char *nss_cmd_NSSCertificateDatabase(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSDBPrefix(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSCipherSuite(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSVerifyClient(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSProtocol(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSNickname(cmd_parms *cmd, void *dcfg, const char *arg); #ifdef SSL_ENABLE_RENEGOTIATION const char *nss_cmd_NSSRenegotiation(cmd_parms *cmd, void *dcfg, int flag); const char *nss_cmd_NSSRequireSafeNegotiation(cmd_parms *cmd, void *dcfg, int flag); #endif #ifdef NSS_ENABLE_ECC const char *nss_cmd_NSSECCNickname(cmd_parms *cmd, void *dcfg, const char *arg); #endif const char *nss_cmd_NSSEnforceValidCerts(cmd_parms *, void *, int); const char *nss_cmd_NSSSessionCacheTimeout(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSSession3CacheTimeout(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSSessionCacheSize(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSPassPhraseDialog(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSPassPhraseHelper(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSRandomSeed(cmd_parms *, void *, const char *, const char *, const char *); const char *nss_cmd_NSSSessionTickets(cmd_parms *cmd, void *dcfg, int flag); const char *nss_cmd_NSSUserName(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSOptions(cmd_parms *, void *, const char *); const char *nss_cmd_NSSRequireSSL(cmd_parms *cmd, void *dcfg); const char *nss_cmd_NSSRequire(cmd_parms *, void *, const char *); const char *nss_cmd_NSSRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSProxyEngine(cmd_parms *cmd, void *dcfg, int flag); const char *nss_cmd_NSSProxyProtocol(cmd_parms *, void *, const char *); const char *nss_cmd_NSSProxyCipherSuite(cmd_parms *, void *, const char *); const char *nss_cmd_NSSProxyNickname(cmd_parms *cmd, void *dcfg, const char *arg); const char *nss_cmd_NSSProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag); const char *set_user(cmd_parms *cmd, void *dummy, const char *arg); /* module initialization */ int nss_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *); void nss_init_Child(apr_pool_t *, server_rec *); void nss_init_ConfigureServer(server_rec *, apr_pool_t *, apr_pool_t *, SSLSrvConfigRec *, const CERTCertList*); apr_status_t nss_init_ModuleKill(void *data); apr_status_t nss_init_ChildKill(void *data); /* int nss_parse_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]); */ /* Apache API hooks */ int nss_hook_UserCheck(request_rec *r); int nss_hook_Fixup(request_rec *r); int nss_hook_Access(request_rec *r); int nss_hook_Auth(request_rec *r); int nss_hook_ReadReq(request_rec *r); /* Variables */ void nss_var_register(void); char *nss_var_lookup(apr_pool_t *, server_rec *, conn_rec *, request_rec *, char *); void nss_var_log_config_register(apr_pool_t *p); APR_DECLARE_OPTIONAL_FN(char *, nss_var_lookup, (apr_pool_t *, server_rec *, conn_rec *, request_rec *, char *)); /* An optional function which returns non-zero if the given connection * is using SSL/TLS. */ APR_DECLARE_OPTIONAL_FN(int, nss_is_https, (conn_rec *)); /* Proxy Support */ int nss_proxy_enable(conn_rec *c); int nss_engine_disable(conn_rec *c); APR_DECLARE_OPTIONAL_FN(int, nss_proxy_enable, (conn_rec *)); APR_DECLARE_OPTIONAL_FN(int, nss_engine_disable, (conn_rec *)); /* I/O */ PRFileDesc * nss_io_new_fd(); int nss_io_layer_init(); void nss_io_filter_init(conn_rec *c, PRFileDesc *ssl); void nss_io_filter_register(apr_pool_t *p); /* Utility Functions */ char *nss_util_vhostid(apr_pool_t *, server_rec *); apr_file_t *nss_util_ppopen(server_rec *, apr_pool_t *, const char *, const char * const *); void nss_util_ppclose(server_rec *, apr_pool_t *, apr_file_t *); char *nss_util_readfilter(server_rec *, apr_pool_t *, const char *, const char * const *); char *searchHashVhostbyNick(char *vhost_id); char *searchHashVhostbyNick_match(char *vhost_id); void addHashVhostNick(char *vhost_id, char *nickname); /* ssl_io_buffer_fill fills the setaside buffering of the HTTP request * to allow an SSL renegotiation to take place. */ int nss_io_buffer_fill(request_rec *r, apr_size_t maxlen); int nss_rand_seed(server_rec *s, apr_pool_t *p, ssl_rsctx_t nCtx, char *prefix); /* Pass Phrase Handling */ SECStatus nss_Init_Tokens(server_rec *s); /* Logging */ #if AP_SERVER_MINORVERSION_NUMBER <= 2 void nss_log_nss_error(const char *file, int line, int level, server_rec *s); #else void nss_log_nss_error(const char *file, int line, int module_index, int level, server_rec *s); #endif void nss_die(void); /* NSS callback */ SECStatus nss_AuthCertificate(void *arg, PRFileDesc *socket, PRBool checksig, PRBool isServer); #endif /* __MOD_NSS_H__ */ mod_nss-1.0.12/mod_nss.spec000066400000000000000000000053621260357105600155660ustar00rootroot00000000000000# BEGIN COPYRIGHT BLOCK # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Copyright (C) 2005 Red Hat, Inc. # All rights reserved. # END COPYRIGHT BLOCK %define product fedora %define _build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.%{flavor}.rpm Summary: mod_nss Name: mod_nss Version: 1.0 Release: 1.%{platform} License: Apache 2.0 Group: System Environment/Daemons URL: http://directory.fedora.redhat.com/ Source: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-root BuildPreReq: httpd-devel,apr-devel # Without Autoreq: 0, rpmbuild finds all sorts of crazy # dependencies that we don't care about, and refuses to install Autoreq: 0 # Don't automatically generate provides list AutoProv: 0 # Without Requires: something, rpmbuild will abort! Requires: httpd,apr Provides: mod_nss Prefix: /opt/%{product}-ds/bin/admin %description An Apache 2.0 module for implementing crypto using the Mozilla NSS crypto libraries. This supports SSLv3/TLSv1 including support for client certificate authentication. NSS provides web applications with a FIPS 140 certified crypto provider and support for a full range of PKCS11 devices. %prep %setup -q %build %ifarch x86_64 ppc64 ia64 s390x mycflags=-m64 %endif if [ %{flavor} = 'dbg' ]; then flag=-g else flag=-O2 fi # configure requires nspr, nss, ldapsdk, adminutil # if can't find apxs, use --with-apxs=/path/to/apxs ./configure --with-apr-config --with-nspr-inc=%{nsprincdir} --with-nspr-lib=%{nsprlibdir} --with-nss-inc=%{nssincdir} --with-nss-lib=%{nsslibdir} CFLAGS="$flag $mycflags" make %install # we don't really want to install this in the system Apache modules dir %{__mkdir_p} $RPM_BUILD_ROOT/%{prefix}/lib %{__mkdir_p} $RPM_BUILD_ROOT/%{prefix}/admin/bin install -m 755 .libs/libmodnss.so $RPM_BUILD_ROOT%{prefix}/lib install -m 755 nss_pcache $RPM_BUILD_ROOT%{prefix}/admin/bin %clean rm -rf $RPM_BUILD_ROOT/$RPM_INSTALL_PREFIX %files # rather than listing individual files, we just package (and own) # the entire ldapserver directory - if we change this to put # files in different places, we won't be able to do this anymore %defattr(-,root,root,-) %{prefix}/lib/libmodnss.so %{prefix}/admin/bin/nss_pcache %changelog * Thu Nov 3 2005 Richard Megginson - 1.0 - Initial version mod_nss-1.0.12/modules.mk000066400000000000000000000010271260357105600152430ustar00rootroot00000000000000mod_nss.la: mod_nss.lo nss_engine_config.lo nss_engine_init.lo nss_engine_io.lo nss_engine_kernel.lo nss_engine_log.lo nss_engine_pphrase.lo nss_engine_vars.lo nss_expr.lo nss_expr_eval.lo nss_expr_parse.lo nss_expr_scan.lo nss_util.lo $(MOD_LINK) mod_nss.lo nss_engine_config.lo nss_engine_init.lo nss_engine_io.lo nss_engine_kernel.lo nss_engine_log.lo nss_engine_pphrase.lo nss_engine_vars.lo nss_expr.lo nss_expr_eval.lo nss_expr_parse.lo nss_expr_scan.lo nss_util.lo DISTCLEAN_TARGETS = modules.mk static = mod_nss.la shared = mod_nss-1.0.12/nss.conf.in000066400000000000000000000223251260357105600153250ustar00rootroot00000000000000# # This is the Apache server configuration file providing SSL support using. # the mod_nss plugin. It contains the configuration directives to instruct # the server how to serve pages over an https connection. # # Do NOT simply read the instructions in here without understanding # what they do. They're here only as hints or reminders. If you are unsure # consult the online docs. You have been warned. # # # When we also provide SSL we have to listen to the # standard HTTP port (see above) and to the HTTPS port # # Note: Configurations that use IPv6 but not IPv4-mapped addresses need two # Listen directives: "Listen [::]:443" and "Listen 0.0.0.0:443" # Listen 443 ## ## SSL Global Context ## ## All SSL configuration in this context applies both to ## the main server and all SSL-enabled virtual hosts. ## # # Some MIME-types for downloading Certificates and CRLs # AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl # Pass Phrase Dialog: # Configure the pass phrase gathering process. # The filtering dialog program (`builtin' is a internal # terminal dialog) has to provide the pass phrase on stdout. NSSPassPhraseDialog builtin # Pass Phrase Helper: # This helper program stores the token password pins between # restarts of Apache. NSSPassPhraseHelper /usr/libexec/nss_pcache # Configure the SSL Session Cache. # NSSSessionCacheSize is the number of entries in the cache. # NSSSessionCacheTimeout is the SSL2 session timeout (in seconds). # NSSSession3CacheTimeout is the SSL3/TLS session timeout (in seconds). NSSSessionCacheSize 10000 NSSSessionCacheTimeout 100 NSSSession3CacheTimeout 86400 # # Pseudo Random Number Generator (PRNG): # Configure one or more sources to seed the PRNG of the SSL library. # The seed data should be of good random quality. # WARNING! On some platforms /dev/random blocks if not enough entropy # is available. Those platforms usually also provide a non-blocking # device, /dev/urandom, which may be used instead. # # This does not support seeding the RNG with each connection. NSSRandomSeed startup builtin #NSSRandomSeed startup file:/dev/random 512 #NSSRandomSeed startup file:/dev/urandom 512 # # TLS Negotiation configuration under RFC 5746 # # Only renegotiate if the peer's hello bears the TLS renegotiation_info # extension. Default off. NSSRenegotiation off # Peer must send Signaling Cipher Suite Value (SCSV) or # Renegotiation Info (RI) extension in ALL handshakes. Default: off NSSRequireSafeNegotiation off ## ## SSL Virtual Host Context ## # General setup for the virtual host #DocumentRoot "@apache_prefix@/htdocs" #ServerName www.example.com:443 #ServerAdmin you@example.com # mod_nss can log to separate log files, you can choose to do that if you'd like # LogLevel is not inherited from httpd.conf. #ErrorLog @apache_prefix@/logs/error_log #TransferLog @apache_prefix@/logs/access_log LogLevel warn # SSL Engine Switch: # Enable/Disable SSL for this virtual host. NSSEngine on # SSL Cipher Suite: # List the ciphers that the client is permitted to negotiate. # See the mod_nss documentation for a complete list. # SSL 3 ciphers. SSL 2 is disabled by default. NSSCipherSuite +rsa_rc4_128_md5,+rsa_rc4_128_sha,+rsa_3des_sha,-rsa_des_sha,-rsa_rc4_40_md5,-rsa_rc2_40_md5,-rsa_null_md5,-rsa_null_sha,+fips_3des_sha,-fips_des_sha,-fortezza,-fortezza_rc4_128_sha,-fortezza_null,-rsa_des_56_sha,-rsa_rc4_56_sha,+rsa_aes_128_sha,+rsa_aes_256_sha # SSL 3 ciphers + ECC ciphers. SSL 2 is disabled by default. # # Comment out the NSSCipherSuite line above and use the one below if you have # ECC enabled NSS and mod_nss and want to use Elliptical Curve Cryptography #NSSCipherSuite +rsa_rc4_128_md5,+rsa_rc4_128_sha,+rsa_3des_sha,-rsa_des_sha,-rsa_rc4_40_md5,-rsa_rc2_40_md5,-rsa_null_md5,-rsa_null_sha,+fips_3des_sha,-fips_des_sha,-fortezza,-fortezza_rc4_128_sha,-fortezza_null,-rsa_des_56_sha,-rsa_rc4_56_sha,+rsa_aes_128_sha,+rsa_aes_256_sha,-ecdh_ecdsa_null_sha,+ecdh_ecdsa_rc4_128_sha,+ecdh_ecdsa_3des_sha,+ecdh_ecdsa_aes_128_sha,+ecdh_ecdsa_aes_256_sha,-ecdhe_ecdsa_null_sha,+ecdhe_ecdsa_rc4_128_sha,+ecdhe_ecdsa_3des_sha,+ecdhe_ecdsa_aes_128_sha,+ecdhe_ecdsa_aes_256_sha,-ecdh_rsa_null_sha,+ecdh_rsa_128_sha,+ecdh_rsa_3des_sha,+ecdh_rsa_aes_128_sha,+ecdh_rsa_aes_256_sha,-echde_rsa_null,+ecdhe_rsa_rc4_128_sha,+ecdhe_rsa_3des_sha,+ecdhe_rsa_aes_128_sha,+ecdhe_rsa_aes_256_sha # SSL Protocol: # Cryptographic protocols that provide communication security. # NSS handles the specified protocols as "ranges", and automatically # negotiates the use of the strongest protocol for a connection starting # with the maximum specified protocol and downgrading as necessary to the # minimum specified protocol that can be used between two processes. # Since all protocol ranges are completely inclusive, and no protocol in the # middle of a range may be excluded, the entry "NSSProtocol SSLv3,TLSv1.1" # is identical to the entry "NSSProtocol SSLv3,TLSv1.0,TLSv1.1". NSSProtocol TLSv1.0,TLSv1.1,TLSv1.2 # SSL Certificate Nickname: # The nickname of the RSA server certificate you are going to use. NSSNickname Server-Cert # SSL Certificate Nickname: # The nickname of the ECC server certificate you are going to use, if you # have an ECC-enabled version of NSS and mod_nss #NSSECCNickname Server-Cert-ecc # Server Certificate Database: # The NSS security database directory that holds the certificates and # keys. The database consists of 3 files: cert8.db, key3.db and secmod.db. # Provide the directory that these files exist. NSSCertificateDatabase @apache_conf@ # Database Prefix: # In order to be able to store multiple NSS databases in one directory # they need unique names. This option sets the database prefix used for # cert8.db and key3.db. #NSSDBPrefix my-prefix- # Client Authentication (Type): # Client certificate verification type. Types are none, optional and # require. #NSSVerifyClient none # # Online Certificate Status Protocol (OCSP). # Verify that certificates have not been revoked before accepting them. #NSSOCSP off # # Use a default OCSP responder. If enabled this will be used regardless # of whether one is included in a client certificate. Note that the # server certificate is verified during startup. # # NSSOCSPDefaultURL defines the service URL of the OCSP responder # NSSOCSPDefaultName is the nickname of the certificate to trust to # sign the OCSP responses. #NSSOCSPDefaultResponder on #NSSOCSPDefaultURL http://example.com/ocsp/status #NSSOCSPDefaultName ocsp-nickname # Access Control: # With SSLRequire you can do per-directory access control based # on arbitrary complex boolean expressions containing server # variable checks and other lookup directives. The syntax is a # mixture between C and Perl. See the mod_nss documentation # for more details. # #NSSRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \ # and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \ # and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \ # and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \ # and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \ # or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/ # # SSL Engine Options: # Set various options for the SSL engine. # o FakeBasicAuth: # Translate the client X.509 into a Basic Authorisation. This means that # the standard Auth/DBMAuth methods can be used for access control. The # user name is the `one line' version of the client's X.509 certificate. # Note that no password is obtained from the user. Every entry in the user # file needs this password: `xxj31ZMTZzkVA'. # o ExportCertData: # This exports two additional environment variables: SSL_CLIENT_CERT and # SSL_SERVER_CERT. These contain the PEM-encoded certificates of the # server (always existing) and the client (only existing when client # authentication is used). This can be used to import the certificates # into CGI scripts. # o StdEnvVars: # This exports the standard SSL/TLS related `SSL_*' environment variables. # Per default this exportation is switched off for performance reasons, # because the extraction step is an expensive operation and is usually # useless for serving static content. So one usually enables the # exportation for CGI and SSI requests only. # o StrictRequire: # This denies access when "NSSRequireSSL" or "NSSRequire" applied even # under a "Satisfy any" situation, i.e. when it applies access is denied # and no other module can change it. # o OptRenegotiate: # This enables optimized SSL connection renegotiation handling when SSL # directives are used in per-directory context. #NSSOptions +FakeBasicAuth +ExportCertData +CompatEnvVars +StrictRequire NSSOptions +StdEnvVars NSSOptions +StdEnvVars # Per-Server Logging: # The home of a custom SSL log file. Use this when you want a # compact non-error SSL logfile on a virtual host basis. #CustomLog /home/rcrit/redhat/apache/logs/ssl_request_log \ # "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" mod_nss-1.0.12/nss_engine_cipher.c000066400000000000000000000574651260357105600171110ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" #include "nss_engine_cipher.h" #include #include #include #include #include /* ciphernum is defined in nss_engine_cipher.h */ cipher_properties ciphers_def[] = { {"rsa_null_md5", TLS_RSA_WITH_NULL_MD5, "NULL-MD5", SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_MD5, SSLV3, SSL_STRONG_NONE, 0, 0}, {"rsa_null_sha", TLS_RSA_WITH_NULL_SHA, "NULL-SHA", SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_SHA1, SSLV3, SSL_STRONG_NONE, 0, 0}, {"rsa_rc4_40_md5", TLS_RSA_EXPORT_WITH_RC4_40_MD5, "EXP-RC4-MD5", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSLV3, SSL_EXPORT40, 40, 128}, {"rsa_rc4_128_md5", TLS_RSA_WITH_RC4_128_MD5, "RC4-MD5", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSLV3, SSL_MEDIUM, 128, 128}, {"rsa_rc4_128_sha", TLS_RSA_WITH_RC4_128_SHA, "RC4-SHA", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1, SSLV3, SSL_MEDIUM, 128, 128}, {"rsa_rc2_40_md5", TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "EXP-RC2-CBC-MD5", SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSLV3, SSL_EXPORT40, 40, 128}, /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA not implemented 0x0008 */ {"rsa_des_sha", TLS_RSA_WITH_DES_CBC_SHA, "DES-CBC-SHA", SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, SSLV3, SSL_LOW, 56, 56}, {"rsa_3des_sha", TLS_RSA_WITH_3DES_EDE_CBC_SHA, "DES-CBC3-SHA", SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_SHA1, SSLV3, SSL_HIGH, 168, 168}, {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA, "AES128-SHA", SSL_kRSA|SSL_aRSA|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128}, {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA, "AES256-SHA", SSL_kRSA|SSL_aRSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, {"null_sha_256", TLS_RSA_WITH_NULL_SHA256, "NULL-SHA256", SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_SHA256, TLSV1_2, SSL_STRONG_NONE, 0, 0}, {"aes_128_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256, "AES128-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128}, {"aes_256_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256, "AES256-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES256|SSL_SHA256, TLSV1_2, SSL_HIGH, 256, 256}, {"camelia_128_sha", TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, "CAMELLIA128-SHA", SSL_kRSA|SSL_aRSA|SSL_CAMELLIA128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128}, {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, "EXP1024-DES-CBC-SHA", SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, TLSV1, SSL_EXPORT56, 56, 56}, {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, "EXP1024-RC4-SHA", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1, TLSV1, SSL_EXPORT56, 56, 128}, {"camelia_256_sha", TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, "CAMELLIA256-SHA", SSL_kRSA|SSL_aRSA|SSL_CAMELLIA256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, #ifdef ENABLE_GCM {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256, "AES128-GCM-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128}, #endif #ifdef ENABLE_SHA384 {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384, "AES256-GCM-SHA384", SSL_kRSA|SSL_aRSA|SSL_AES256GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256}, #endif {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, "FIPS-DES-CBC3-SHA", SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_SHA1, SSLV3, SSL_HIGH, 112, 168}, {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA, "FIPS-DES-CBC-SHA", SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, SSLV3, SSL_LOW, 56, 56}, #ifdef NSS_ENABLE_ECC {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA, "ECDH-ECDSA-NULL-SHA", SSL_kECDHe|SSL_aECDH|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0}, {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA, "ECDH-ECDSA-RC4-SHA", SSL_kECDHe|SSL_aECDH|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128}, {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, "ECDH-ECDSA-DES-CBC3-SHA", SSL_kECDHe|SSL_aECDH|SSL_3DES|SSL_SHA1, TLSV1, SSL_HIGH, 112, 168}, {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, "ECDH-ECDSA-AES128-SHA", SSL_kECDHe|SSL_aECDH|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128}, {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, "ECDH-ECDSA-AES256-SHA", SSL_kECDHe|SSL_aECDH|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA, "ECDHE-ECDSA-NULL-SHA", SSL_kEECDH|SSL_aECDSA|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0}, {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "ECDHE-ECDSA-RC4-SHA", SSL_kEECDH|SSL_aECDSA|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128}, {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, "ECDHE-ECDSA-DES-CBC3-SHA", SSL_kEECDH|SSL_aECDSA|SSL_3DES|SSL_SHA1, TLSV1, SSL_HIGH, 112, 168}, {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "ECDHE-ECDSA-AES128-SHA", SSL_kEECDH|SSL_aECDSA|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128}, {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "ECDHE-ECDSA-AES256-SHA", SSL_kEECDH|SSL_aECDSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA, "ECDH-RSA-NULL-SHA", SSL_kECDHr|SSL_aECDH|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0}, {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA, "ECDH-RSA-RC4-SHA", SSL_kECDHr|SSL_aECDH|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128}, {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, "ECDH-RSA-DES-CBC3-SHA", SSL_kECDHr|SSL_aECDH|SSL_3DES|SSL_SHA1, TLSV1, SSL_HIGH, 112, 168}, {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, "ECDH-RSA-AES128-SHA", SSL_kECDHr|SSL_aECDH|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128}, {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, "ECDH-RSA-AES256-SHA", SSL_kECDHr|SSL_aECDH|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA, "ECDHE-RSA-NULL-SHA", SSL_kEECDH|SSL_aRSA|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0}, {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA, "ECDHE-RSA-RC4-SHA", SSL_kEECDH|SSL_aRSA|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128}, {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "ECDHE-RSA-DES-CBC3-SHA", SSL_kEECDH|SSL_aRSA|SSL_3DES|SSL_SHA1, TLSV1, SSL_HIGH, 112, 168}, {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "ECDHE-RSA-AES128-SHA", SSL_kEECDH|SSL_aRSA|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128}, {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "ECDHE-RSA-AES256-SHA", SSL_kEECDH|SSL_aRSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA, "AECDH-NULL-SHA", SSL_kEECDH|SSL_aNULL|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0}, {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA, "AECDH-RC4-SHA", SSL_kEECDH|SSL_aNULL|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128}, {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, "AECDH-DES-CBC3-SHA", SSL_kEECDH|SSL_aNULL|SSL_3DES|SSL_SHA1, TLSV1, SSL_HIGH, 112, 168}, {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA, "AECDH-AES128-SHA", SSL_kEECDH|SSL_aNULL|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128}, {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA, "AECDH-AES256-SHA", SSL_kEECDH|SSL_aNULL|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, {"ecdhe_ecdsa_aes_128_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "ECDHE-ECDSA-AES128-SHA256", SSL_kEECDH|SSL_aECDSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128}, {"ecdhe_rsa_aes_128_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "ECDHE-RSA-AES128-SHA256", SSL_kEECDH|SSL_aRSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128}, #ifdef ENABLE_GCM {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "ECDHE-ECDSA-AES128-GCM-SHA256", SSL_kEECDH|SSL_aECDSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128}, #endif #ifdef ENABLE_SHA384 {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, "ECDHE-ECDSA-AES256-SHA384", SSL_kEECDH|SSL_aECDSA|SSL_AES256|SSL_SHA384, TLSV1_2, SSL_HIGH, 256, 256}, {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, "ECDHE-RSA-AES256-SHA384", SSL_kEECDH|SSL_aRSA|SSL_AES256|SSL_SHA384, TLSV1_2, SSL_HIGH, 256, 256}, {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "ECDHE-ECDSA-AES256-GCM-SHA384", SSL_kEECDH|SSL_aECDSA|SSL_AES256GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256}, {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "ECDHE-RSA-AES256-GCM-SHA384", SSL_kEECDH|SSL_aRSA|SSL_AES256GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256}, #endif #ifdef ENABLE_GCM {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "ECDHE-RSA-AES128-GCM-SHA256", SSL_kEECDH|SSL_aRSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128}, #endif /* TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 is not implemented */ /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 is not implemented */ /* TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 is not implemented */ /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 is not implemented */ #endif }; #define CIPHERNUM sizeof(ciphers_def) / sizeof(cipher_properties) int ciphernum = CIPHERNUM; /* Some ciphers are optionally enabled in OpenSSL. For safety sake assume * they are not available. */ static int skip_ciphers = 4; static int ciphers_not_in_openssl[] = { SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, }; static int parse_nss_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]); static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]); int countciphers(PRBool cipher_state[ciphernum], int version) { int ciphercount = 0; int i = ciphernum; for (i = 0; i < ciphernum; i++) { if ((cipher_state[i] == PR_TRUE) && (ciphers_def[i].version & version)) { ciphercount++; } } return ciphercount; } int nss_parse_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]) { int rv = 0; /* If the string has a colon we use the OpenSSL style. If it has a * comma then NSS. If it has neither we try both. */ if (strchr(ciphers, ':')) { rv = parse_openssl_ciphers(s, ciphers, cipher_list); } else if (strchr(ciphers, ',')) { rv = parse_nss_ciphers(s, ciphers, cipher_list); } else { rv = parse_openssl_ciphers(s, ciphers, cipher_list); if (rv == 0 && 0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2)) { rv = parse_nss_ciphers(s, ciphers, cipher_list); } } if (0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2)) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "no cipher match"); } return rv; } /* Given a set of ciphers perform a given action on the indexed value. * * This is needed because the + action doesn't do anything in the NSS * context. In OpenSSL it will re-order the cipher list. */ static void set_cipher_value(PRBool cipher_list[ciphernum], int index, int action) { int i; for (i = 0; i < skip_ciphers; i++) { if (ciphers_def[index].num == ciphers_not_in_openssl[i]) { cipher_list[index] = -1; return; } } if (cipher_list[index] != -1) /* cipher is disabled */ cipher_list[index] = action; } static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]) { char * cipher; int i, action; PRBool merge = PR_FALSE; PRBool found = PR_FALSE; PRBool first = PR_TRUE; cipher = ciphers; while (ciphers && (strlen(ciphers))) { while ((*cipher) && (isspace(*cipher))) ++cipher; action = 1; /* default to enable */ switch(*cipher) { case '+': /* Add something */ /* Cipher ordering is not supported in NSS */ return 0; break; case '-': /* Subtract something */ action = 0; cipher++; break; case '!': /* Disable something */ action = -1; cipher++; break; default: /* do nothing */ break; } if ((ciphers = strchr(cipher, ':'))) { *ciphers++ = '\0'; merge = PR_FALSE; found = PR_FALSE; } if (!strcmp(cipher, "ALL")) { found = PR_TRUE; for (i=0; iprocess->pool; SSLModConfigRec *mc; void *vmc; apr_pool_userdata_get(&vmc, SSL_MOD_CONFIG_KEY, pool); if (vmc) { return vmc; /* reused for lifetime of the server */ } /* * allocate an own subpool which survives server restarts */ mc = (SSLModConfigRec *)apr_palloc(pool, sizeof(*mc)); mc->pPool = pool; /* * initialize per-module configuration */ mc->nInitCount = 0; mc->pCertificateDatabase = NULL; mc->pDBPrefix = NULL; mc->session_cache_size = UNSET; mc->session_cache_timeout = UNSET; mc->ssl3_session_cache_timeout = UNSET; mc->pphrase_dialog_helper = NULL; mc->pphrase_dialog_path = NULL; mc->aRandSeed = apr_array_make(pool, 4, sizeof(ssl_randseed_t)); mc->semid = 0; apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY, apr_pool_cleanup_null, pool); return mc; } /* _________________________________________________________________ ** ** Configuration handling ** _________________________________________________________________ */ static void modnss_ctx_init(modnss_ctx_t *mctx) { mctx->sc = NULL; /* set during module init */ mctx->as_server = PR_TRUE; mctx->ssl3 = PR_FALSE; mctx->tls = PR_FALSE; mctx->tlsrollback = PR_FALSE; #ifdef SSL_ENABLE_RENEGOTIATION mctx->enablerenegotiation = PR_FALSE; mctx->requiresafenegotiation = PR_FALSE; #endif mctx->enforce = PR_TRUE; mctx->nickname = NULL; #ifdef NSS_ENABLE_ECC mctx->eccnickname = NULL; mctx->eccservercert = NULL; mctx->eccserverkey = NULL; #endif mctx->servercert = NULL; mctx->serverkey = NULL; mctx->model = NULL; mctx->auth.protocols = NULL; mctx->auth.cipher_suite = NULL; mctx->auth.verify_mode = SSL_CVERIFY_UNSET; } static void modnss_ctx_init_proxy(SSLSrvConfigRec *sc, apr_pool_t *p) { modnss_ctx_t *mctx; mctx = sc->proxy = apr_palloc(p, sizeof(*sc->proxy)); modnss_ctx_init(mctx); mctx->as_server = PR_FALSE; } static void modnss_ctx_init_server(SSLSrvConfigRec *sc, apr_pool_t *p) { modnss_ctx_t *mctx; mctx = sc->server = apr_palloc(p, sizeof(*sc->server)); modnss_ctx_init(mctx); mctx->as_server = PR_TRUE; } static SSLSrvConfigRec *nss_config_server_new(apr_pool_t *p) { SSLSrvConfigRec *sc = apr_palloc(p, sizeof(*sc)); sc->mc = NULL; sc->ocsp = UNSET; sc->ocsp_default = UNSET; sc->ocsp_url = NULL; sc->ocsp_name = NULL; sc->fips = UNSET; sc->enabled = UNSET; sc->sni = TRUE; sc->strict_sni_vhost_check = TRUE; sc->proxy_enabled = UNSET; sc->vhost_id = NULL; /* set during module init */ sc->vhost_id_len = 0; /* set during module init */ sc->proxy = NULL; sc->server = NULL; sc->proxy_ssl_check_peer_cn = TRUE; sc->session_tickets = FALSE; modnss_ctx_init_proxy(sc, p); modnss_ctx_init_server(sc, p); return sc; } /* * Create per-server SSL configuration */ void *nss_config_server_create(apr_pool_t *p, server_rec *s) { SSLSrvConfigRec *sc = nss_config_server_new(p); sc->mc = nss_config_global_create(s); return sc; } #define cfgMerge(el,unset) mrg->el = (add->el == (unset)) ? base->el : add->el #define cfgMergeArray(el) mrg->el = apr_array_append(p, add->el, base->el) #define cfgMergeString(el) cfgMerge(el, NULL) #define cfgMergeBool(el) cfgMerge(el, UNSET) #define cfgMergeInt(el) cfgMerge(el, UNSET) static void modnss_ctx_cfg_merge(modnss_ctx_t *base, modnss_ctx_t *add, modnss_ctx_t *mrg) { cfgMerge(auth.protocols, NULL); cfgMerge(auth.cipher_suite, NULL); cfgMerge(auth.verify_mode, SSL_CVERIFY_UNSET); cfgMerge(nickname, NULL); #ifdef NSS_ENABLE_ECC cfgMerge(eccnickname, NULL); #endif cfgMerge(enforce, PR_TRUE); #ifdef SSL_ENABLE_RENEGOTIATION cfgMerge(enablerenegotiation, PR_FALSE); cfgMerge(requiresafenegotiation, PR_FALSE); #endif } static void modnss_ctx_cfg_merge_proxy(modnss_ctx_t *base, modnss_ctx_t *add, modnss_ctx_t *mrg) { modnss_ctx_cfg_merge(base, add, mrg); } static void modnss_ctx_cfg_merge_server(modnss_ctx_t *base, modnss_ctx_t *add, modnss_ctx_t *mrg) { modnss_ctx_cfg_merge(base, add, mrg); } /* * Merge per-server SSL configurations */ void *nss_config_server_merge(apr_pool_t *p, void *basev, void *addv) { SSLSrvConfigRec *base = (SSLSrvConfigRec *)basev; SSLSrvConfigRec *add = (SSLSrvConfigRec *)addv; SSLSrvConfigRec *mrg = nss_config_server_new(p); cfgMerge(mc, NULL); cfgMergeBool(ocsp); cfgMergeBool(ocsp_default); cfgMerge(ocsp_url, NULL); cfgMerge(ocsp_name, NULL); cfgMergeBool(fips); cfgMergeBool(enabled); cfgMergeBool(sni); cfgMergeBool(strict_sni_vhost_check); cfgMergeBool(proxy_enabled); cfgMergeBool(proxy_ssl_check_peer_cn); cfgMergeBool(session_tickets); modnss_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy); modnss_ctx_cfg_merge_server(base->server, add->server, mrg->server); return mrg; } /* * Create per-directory SSL configuration */ void *nss_config_perdir_create(apr_pool_t *p, char *dir) { SSLDirConfigRec *dc = apr_palloc(p, sizeof(*dc)); dc->bSSLRequired = FALSE; dc->aRequirement = apr_array_make(p, 4, sizeof(nss_require_t)); dc->nOptions = SSL_OPT_NONE|SSL_OPT_RELSET; dc->nOptionsAdd = SSL_OPT_NONE; dc->nOptionsDel = SSL_OPT_NONE; dc->szCipherSuite = NULL; dc->nVerifyClient = SSL_CVERIFY_UNSET; dc->szUserName = NULL; dc->nRenegBufferSize = UNSET; return dc; } const char *nss_cmd_NSSRequireSSL(cmd_parms *cmd, void *dcfg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->bSSLRequired = TRUE; return NULL; } const char *nss_cmd_NSSRequire(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; nss_expr *expr; nss_require_t *require; if (!(expr = nss_expr_comp(cmd->pool, (char *)arg))) { return apr_pstrcat(cmd->pool, "NSSRequire: ", nss_expr_get_error(), NULL); } require = apr_array_push(dc->aRequirement); require->cpExpr = apr_pstrdup(cmd->pool, arg); require->mpExpr = expr; return NULL; } const char *nss_cmd_NSSRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = dcfg; int val; val = atoi(arg); if (val < 0) { return apr_pstrcat(cmd->pool, "Invalid size for NSSRenegBufferSize: ", arg, NULL); } dc->nRenegBufferSize = val; return NULL; } void *nss_config_perdir_merge(apr_pool_t *p, void *basev, void *addv) { SSLDirConfigRec *base = (SSLDirConfigRec *)basev; SSLDirConfigRec *add = (SSLDirConfigRec *)addv; SSLDirConfigRec *mrg = (SSLDirConfigRec *)apr_palloc(p, sizeof(*mrg)); cfgMerge(bSSLRequired, FALSE); cfgMergeArray(aRequirement); if (add->nOptions & SSL_OPT_RELSET) { mrg->nOptionsAdd = (base->nOptionsAdd & ~(add->nOptionsDel)) | add->nOptionsAdd; mrg->nOptionsDel = (base->nOptionsDel & ~(add->nOptionsAdd)) | add->nOptionsDel; mrg->nOptions = (base->nOptions & ~(mrg->nOptionsDel)) | mrg->nOptionsAdd; } else { mrg->nOptions = add->nOptions; mrg->nOptionsAdd = add->nOptionsAdd; mrg->nOptionsDel = add->nOptionsDel; } cfgMergeString(szCipherSuite); cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET); cfgMergeString(szUserName); cfgMergeInt(nRenegBufferSize); return mrg; } const char *nss_cmd_NSSEngine(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->enabled = flag ? TRUE : FALSE; return NULL; } const char *nss_cmd_NSSFIPS(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->fips = flag ? TRUE : FALSE; return NULL; } const char *nss_cmd_NSSSNI(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->sni = flag ? TRUE : FALSE; return NULL; } const char *nss_cmd_NSSStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->strict_sni_vhost_check = flag ? TRUE : FALSE; return NULL; } const char *nss_cmd_NSSOCSP(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->ocsp = flag ? TRUE : FALSE; return NULL; } const char *nss_cmd_NSSOCSPDefaultResponder(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->ocsp_default = flag ? TRUE : FALSE; return NULL; } const char *nss_cmd_NSSOCSPDefaultURL(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->ocsp_url = arg; return NULL; } const char *nss_cmd_NSSOCSPDefaultName(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->ocsp_name = arg; return NULL; } const char *nss_cmd_NSSCertificateDatabase(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); mc->pCertificateDatabase = arg; return NULL; } const char *nss_cmd_NSSDBPrefix(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); mc->pDBPrefix = arg; return NULL; } const char *nss_cmd_NSSCipherSuite(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; if (cmd->path) { dc->szCipherSuite = arg; } else { sc->server->auth.cipher_suite = arg; } return NULL; } static const char *nss_cmd_verify_parse(cmd_parms *parms, const char *arg, nss_verify_t *id) { if (strcEQ(arg, "none") || strcEQ(arg, "off")) { *id = SSL_CVERIFY_NONE; } else if (strcEQ(arg, "optional")) { *id = SSL_CVERIFY_OPTIONAL; } else if (strcEQ(arg, "require") || strcEQ(arg, "on")) { *id = SSL_CVERIFY_REQUIRE; } else if (strcEQ(arg, "optional_no_ca")) { return apr_pstrcat(parms->temp_pool, parms->cmd->name, "SSL_CVERIFY_OPTIONAL_NO_CA is not supported", NULL); } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Invalid argument '", arg, "'", NULL); } return NULL; } const char *nss_cmd_NSSVerifyClient(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; SSLSrvConfigRec *sc = mySrvConfig(cmd->server); nss_verify_t mode = SSL_CVERIFY_UNSET; const char *err; if ((err = nss_cmd_verify_parse(cmd, arg, &mode))) { return err; } if (cmd->path) { dc->nVerifyClient = mode; } else { sc->server->auth.verify_mode = mode; } return NULL; } const char *nss_cmd_NSSProtocol(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->auth.protocols = arg; return NULL; } const char *nss_cmd_NSSNickname(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->nickname = arg; return NULL; } #ifdef SSL_ENABLE_RENEGOTIATION const char *nss_cmd_NSSRenegotiation(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->enablerenegotiation = flag ? PR_TRUE : PR_FALSE; return NULL; } const char *nss_cmd_NSSRequireSafeNegotiation(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->requiresafenegotiation = flag ? PR_TRUE : PR_FALSE; return NULL; } #endif #ifdef NSS_ENABLE_ECC const char *nss_cmd_NSSECCNickname(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->eccnickname = arg; return NULL; } #endif const char *nss_cmd_NSSProxyEngine(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->proxy_enabled = flag ? TRUE : FALSE; return NULL; } const char *nss_cmd_NSSProxyProtocol(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->proxy->auth.protocols = arg; return NULL; } const char *nss_cmd_NSSProxyCipherSuite(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->proxy->auth.cipher_suite = arg; return NULL; } const char *nss_cmd_NSSProxyNickname(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->proxy->nickname = arg; return NULL; } const char *nss_cmd_NSSProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->proxy_ssl_check_peer_cn = flag ? TRUE : FALSE; return NULL; } const char *nss_cmd_NSSEnforceValidCerts(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->server->enforce = flag ? PR_TRUE : PR_FALSE; return NULL; } const char *nss_cmd_NSSSessionCacheTimeout(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); /* Deprecated. Store a value, if any, just to complain about it later. */ mc->session_cache_timeout = atoi(arg); return NULL; } const char *nss_cmd_NSSSession3CacheTimeout(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); mc->ssl3_session_cache_timeout = atoi(arg); if (mc->ssl3_session_cache_timeout < 0) { return "NSSSession3CacheTimeout: Invalid argument"; } return NULL; } const char *nss_cmd_NSSSessionCacheSize(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); mc->session_cache_size = atoi(arg); if (mc->session_cache_size < 0) { return "NSSSessionCacheTimeout: Invalid argument"; } return NULL; } const char *nss_cmd_NSSPassPhraseDialog(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); int arglen = strlen(arg); if (strcEQ(arg, "builtin")) { mc->pphrase_dialog_type = SSL_PPTYPE_BUILTIN; mc->pphrase_dialog_path = NULL; } else if (((arglen > 5) && strEQn(arg, "file:", 5)) || ((arglen > 6) && strEQn(arg, "defer:", 6))) { apr_finfo_t finfo; apr_status_t rc; if (strEQn(arg, "file:", 5)) { mc->pphrase_dialog_type = SSL_PPTYPE_FILE; mc->pphrase_dialog_path = ap_server_root_relative(cmd->pool, arg+5); } else { mc->pphrase_dialog_type = SSL_PPTYPE_DEFER; mc->pphrase_dialog_path = ap_server_root_relative(cmd->pool, arg+6); } if (!mc->pphrase_dialog_path) return apr_pstrcat(cmd->pool, "Invalid NSSPassPhraseDialog file: path ", arg+5, NULL); rc = apr_stat(&finfo, mc->pphrase_dialog_path, APR_FINFO_TYPE|APR_FINFO_SIZE, cmd->pool); if ((rc != APR_SUCCESS) || (finfo.filetype != APR_REG)) { return apr_pstrcat(cmd->pool, "NSSPassPhraseDialog: file '", mc->pphrase_dialog_path, "' does not exist", NULL); } } return NULL; } const char *nss_cmd_NSSPassPhraseHelper(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); if (access(arg, R_OK|X_OK) != -1) { mc->pphrase_dialog_helper = arg; } else { return apr_pstrcat(cmd->pool, "NSSPassPhraseHelper: ", arg, " does not exist or is not executable.", NULL); } return NULL; } const char *nss_cmd_NSSRandomSeed(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2, const char *arg3) { SSLModConfigRec *mc = myModConfig(cmd->server); const char *err; ssl_randseed_t *seed; int arg2len = strlen(arg2); if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } /* Only run through this once. Otherwise the random seed sources are * pushed into the array for each server start (and we are guaranteed 2) */ if (mc->nInitCount >= 1) { return NULL; } seed = apr_array_push(mc->aRandSeed); if (strcEQ(arg1, "startup")) { seed->nCtx = SSL_RSCTX_STARTUP; } else if (strcEQ(arg1, "connect")) { return apr_pstrcat(cmd->pool, "NSSRandomSeed: " "mod_nss doesn't do per-connection random seeding", NULL); } else { return apr_pstrcat(cmd->pool, "NSSRandomSeed: " "invalid context: `", arg1, "'", NULL); } if ((arg2len > 5) && strEQn(arg2, "file:", 5)) { seed->nSrc = SSL_RSSRC_FILE; seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5); } else if ((arg2len > 5) && strEQn(arg2, "exec:", 5)) { seed->nSrc = SSL_RSSRC_EXEC; seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5); } else if ((arg2len > 6) && strEQn(arg2, "defer:", 6)) { seed->nSrc = SSL_RSSRC_FILE; seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5); } else if (strcEQ(arg2, "builtin")) { seed->nSrc = SSL_RSSRC_BUILTIN; seed->cpPath = NULL; } else { seed->nSrc = SSL_RSSRC_FILE; seed->cpPath = ap_server_root_relative(mc->pPool, arg2); } if (seed->nSrc != SSL_RSSRC_BUILTIN) { apr_finfo_t finfo; if (!seed->cpPath) { return apr_pstrcat(cmd->pool, "Invalid NSSRandomSeed path ", arg2, NULL); } if (apr_stat(&finfo, seed->cpPath, APR_FINFO_TYPE|APR_FINFO_SIZE, cmd->pool) != 0) { return apr_pstrcat(cmd->pool, "NSSRandomSeed: source path '", seed->cpPath, "' does not exist", NULL); } } if (!arg3) { seed->nBytes = 0; /* read whole file */ } else { if (seed->nSrc == SSL_RSSRC_BUILTIN) { return "NSSRandomSeed: byte specification not " "allowed for builtin seed source"; } seed->nBytes = atoi(arg3); if (seed->nBytes < 0) { return "NSSRandomSeed: invalid number of bytes specified"; } } return NULL; } const char *nss_cmd_NSSSessionTickets(cmd_parms *cmd, void *dcfg, int flag) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->session_tickets = flag ? PR_TRUE : PR_FALSE; return NULL; } const char *nss_cmd_NSSUserName(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; dc->szUserName = arg; return NULL; } const char *nss_cmd_NSSOptions(cmd_parms *cmd, void *dcfg, const char *arg) { SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; nss_opt_t opt; int first = TRUE; char action, *w; while (*arg) { w = ap_getword_conf(cmd->pool, &arg); action = NUL; if ((*w == '+') || (*w == '-')) { action = *(w++); } else if (first) { dc->nOptions = SSL_OPT_NONE; first = FALSE; } if (strcEQ(w, "StdEnvVars")) { opt = SSL_OPT_STDENVVARS; } else if (strcEQ(w, "CompatEnvVars")) { opt = SSL_OPT_COMPATENVVARS; } else if (strcEQ(w, "ExportCertData")) { opt = SSL_OPT_EXPORTCERTDATA; } else if (strcEQ(w, "FakeBasicAuth")) { opt = SSL_OPT_FAKEBASICAUTH; } else if (strcEQ(w, "StrictRequire")) { opt = SSL_OPT_STRICTREQUIRE; } else if (strcEQ(w, "OptRenegotiate")) { opt = SSL_OPT_OPTRENEGOTIATE; } else { return apr_pstrcat(cmd->pool, "NSSOptions: Illegal option '", w, "'", NULL); } if (action == '-') { dc->nOptionsAdd &= ~opt; dc->nOptionsDel |= opt; dc->nOptions &= ~opt; } else if (action == '+') { dc->nOptionsAdd |= opt; dc->nOptionsDel &= ~opt; dc->nOptions |= opt; } else { dc->nOptions = opt; dc->nOptionsAdd = opt; dc->nOptionsDel = SSL_OPT_NONE; } } return NULL; } const char *set_user(cmd_parms *cmd, void *dummy, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); mc->user = arg; return NULL; } mod_nss-1.0.12/nss_engine_init.c000066400000000000000000001711611260357105600165700ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" #include "nss_engine_cipher.h" #include "apr_thread_proc.h" #include "apr_strings.h" #include "mpm_common.h" #if AP_SERVER_MINORVERSION_NUMBER <= 2 #include "ap_mpm.h" #endif #include "secmod.h" #include "sslerr.h" #include "pk11func.h" #include "ocsp.h" #include "keyhi.h" #include "cert.h" static SECStatus ownBadCertHandler(void *arg, PRFileDesc * socket); static SECStatus ownHandshakeCallback(PRFileDesc * socket, void *arg); static SECStatus NSSHandshakeCallback(PRFileDesc *socket, void *arg); static CERTCertificate* FindServerCertFromNickname(const char* name, const CERTCertList* clist); SECStatus nss_AuthCertificate(void *arg, PRFileDesc *socket, PRBool checksig, PRBool isServer); PRInt32 nssSSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr, PRUint32 sniNameArrSize, void *arg); /* * Global variables defined in this file. */ char* INTERNAL_TOKEN_NAME = "internal "; extern cipher_properties ciphers_def[]; static char *version_components[] = { "SSL_VERSION_PRODUCT", "SSL_VERSION_INTERFACE", "SSL_VERSION_LIBRARY", NULL }; static char *nss_add_version_component(apr_pool_t *p, server_rec *s, char *name) { char *val = nss_var_lookup(p, s, NULL, NULL, name); if (val && *val) { ap_add_version_component(p, val); } return val; } static void nss_add_version_components(apr_pool_t *p, server_rec *s) { char *vals[sizeof(version_components)/sizeof(char *)]; int i; for (i=0; version_components[i]; i++) { vals[i] = nss_add_version_component(p, s, version_components[i]); } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Server: %s, Interface: %s, Library: %s", AP_SERVER_BASEVERSION, vals[1], /* SSL_VERSION_INTERFACE */ vals[2]); /* SSL_VERSION_LIBRARY */ } /* * Initialize SSL library * */ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p) { SECStatus rv; SSLModConfigRec *mc = myModConfig(base_server); SSLSrvConfigRec *sc; char cwd[PATH_MAX]; server_rec *s; int fipsenabled = FALSE; int ocspenabled = FALSE; int ocspdefault = FALSE; int snienabled = FALSE; char *dbdir = NULL; const char * ocspurl = NULL; const char * ocspname = NULL; for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); if (sc->fips == TRUE) { fipsenabled = TRUE; } if (sc->ocsp == TRUE) { ocspenabled = TRUE; } if (sc->ocsp_default == TRUE) { ocspdefault = TRUE; ocspurl = sc->ocsp_url; ocspname = sc->ocsp_name; if ((ocspurl == NULL) || (ocspname == NULL)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "When NSSOCSPDefaultResponder is enabled both a default URL (NSSOCSPDefaultUrl) and certificate nickname (NSSOCSPDefaultName) are required."); if (mc->nInitCount == 1) nss_die(); else return; } } if (sc->sni == TRUE) { snienabled = TRUE; } } /* We need to be in the same directory as libnssckbi.so to load the * root certificates properly. */ if (getcwd(cwd, PATH_MAX) == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Unable to determine current working directory"); if (mc->nInitCount == 1) nss_die(); else return; } if (strncasecmp(mc->pCertificateDatabase, "sql:", 4) == 0) dbdir = (char *)mc->pCertificateDatabase + 4; else dbdir = (char *)mc->pCertificateDatabase; if (chdir(dbdir) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Unable to change directory to %s", mc->pCertificateDatabase); ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Does the directory exist and do the permissions allow access?"); if (mc->nInitCount == 1) nss_die(); else return; } /* Initialize NSS and open the certificate database read-only. */ rv = NSS_Initialize(mc->pCertificateDatabase, mc->pDBPrefix, mc->pDBPrefix, "secmod.db", NSS_INIT_READONLY); if (chdir(cwd) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Unable to change directory to %s", cwd); ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Does the directory exist and do the permissions allow access?"); if (mc->nInitCount == 1) nss_die(); else return; } /* Assuming everything is ok so far, check the cert database password(s). */ if (rv != SECSuccess) { apr_finfo_t finfo; char keypath[1024]; int rv; uid_t user_id; gid_t gid; user_id = ap_uname2id(mc->user); gid = getegid(); NSS_Shutdown(); ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "NSS_Initialize failed. Certificate database: %s.", mc->pCertificateDatabase != NULL ? mc->pCertificateDatabase : "not set in configuration"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, base_server); apr_snprintf(keypath, 1024, "%s/key3.db", mc->pCertificateDatabase); if ((rv = apr_stat(&finfo, keypath, APR_FINFO_PROT | APR_FINFO_OWNER, p)) == APR_SUCCESS) { if (((user_id == finfo.user) && (!(finfo.protection & APR_FPROT_UREAD))) || ((gid == finfo.group) && (!(finfo.protection & APR_FPROT_GREAD))) || (!(finfo.protection & APR_FPROT_WREAD)) ) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Server user lacks read access to NSS database."); } } else { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Does the NSS database exist?"); } nss_die(); } if (fipsenabled) { if (!PK11_IsFIPS()) { char * internal_name = PR_smprintf("%s", SECMOD_GetInternalModule()->commonName); if ((SECMOD_DeleteInternalModule(internal_name) != SECSuccess) || !PK11_IsFIPS()) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Unable to enable FIPS mode on certificate database %s.", mc->pCertificateDatabase); NSS_Shutdown(); nss_log_nss_error(APLOG_MARK, APLOG_ERR, base_server); if (mc->nInitCount == 1) nss_die(); else return; } PR_smprintf_free(internal_name); } /* FIPS is already enabled, nothing to do */ } if (nss_Init_Tokens(base_server) != SECSuccess) { NSS_Shutdown(); ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "NSS initialization failed. Certificate database: %s.", mc->pCertificateDatabase != NULL ? mc->pCertificateDatabase : "not set in configuration"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, base_server); if (mc->nInitCount == 1) nss_die(); else return; } if (NSS_SetDomesticPolicy() != SECSuccess) { NSS_Shutdown(); ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "NSS set domestic policy failed on certificate database %s.", mc->pCertificateDatabase); nss_log_nss_error(APLOG_MARK, APLOG_ERR, base_server); if (mc->nInitCount == 1) nss_die(); else return; } if (ocspenabled) { CERT_EnableOCSPChecking(CERT_GetDefaultCertDB()); ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, "OCSP is enabled."); /* We ensure that ocspname and ocspurl are not NULL above. */ if (ocspdefault) { SECStatus sv; sv = CERT_SetOCSPDefaultResponder(CERT_GetDefaultCertDB(), ocspurl, ocspname); if (sv == SECFailure) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Unable to set OCSP default responder nickname %s.", ocspname); nss_log_nss_error(APLOG_MARK, APLOG_ERR, base_server); if (mc->nInitCount == 1) nss_die(); else return; } sv = CERT_EnableOCSPDefaultResponder(CERT_GetDefaultCertDB()); if (sv == SECFailure) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Unable to enable the OCSP default responder, %s (this shouldn't happen).", ocspname); nss_log_nss_error(APLOG_MARK, APLOG_ERR, base_server); if (mc->nInitCount == 1) nss_die(); else return; } } } if (snienabled) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, "SNI is enabled"); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, "SNI is disabled"); } /* * Seed the Pseudo Random Number Generator (PRNG) * only need ptemp here; nothing inside allocated from the pool * needs to live once we return from nss_rand_seed(). */ nss_rand_seed(base_server, mc->ptemp, SSL_RSCTX_STARTUP, "Init: "); } int nss_init_Module(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *base_server) { SSLModConfigRec *mc = myModConfig(base_server); SSLSrvConfigRec *sc; server_rec *s; int sslenabled = FALSE; int fipsenabled = FALSE; int threaded = 0; struct semid_ds status; char *split_vhost_id = NULL; char *last1; mc->nInitCount++; /* * Let us cleanup on restarts and exists */ apr_pool_cleanup_register(p, base_server, nss_init_ModuleKill, apr_pool_cleanup_null); mc->ptemp = ptemp; /* * Any init round fixes the global config */ nss_config_global_create(base_server); /* just to avoid problems */ /* * Fix up any global settings that aren't in the configuration */ if (mc->session_cache_timeout != UNSET) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, "NSSSessionCacheTimeout is deprecated. Ignoring."); /* We still need to pass in a legal value to * SSL_ConfigMPServerSIDCache() and SSL_ConfigServerSessionIDCache() */ mc->session_cache_timeout = 0; /* use NSS default */ } if (mc->ssl3_session_cache_timeout == UNSET) { mc->ssl3_session_cache_timeout = SSL3_SESSION_CACHE_TIMEOUT; } if (mc->session_cache_size == UNSET) { mc->session_cache_size = SSL_SESSION_CACHE_SIZE; } if (mc->pphrase_dialog_type == SSL_PPTYPE_UNSET) { mc->pphrase_dialog_type = SSL_PPTYPE_BUILTIN; } /* * try to fix the configuration and open the dedicated SSL * logfile as early as possible */ for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); if (sc->server) { sc->server->sc = sc; } if (sc->proxy) { sc->proxy->sc = sc; } /* * Create the server host:port string because we need it a lot */ sc->vhost_id = nss_util_vhostid(p, s); sc->vhost_id_len = strlen(sc->vhost_id); if (sc->sni && sc->server->nickname != NULL && sc->vhost_id != NULL) { split_vhost_id = apr_strtok((char *)sc->vhost_id, ":", &last1); ap_str_tolower(split_vhost_id); addHashVhostNick(split_vhost_id, (char *)sc->server->nickname); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SNI: %s -> %s", split_vhost_id, (char *)sc->server->nickname); } /* Fix up stuff that may not have been set */ if (sc->fips == UNSET) { sc->fips = FALSE; } if (sc->ocsp == UNSET) { sc->ocsp = FALSE; } if (sc->ocsp_default == UNSET) { sc->ocsp_default = FALSE; } /* If any servers have SSL, we want sslenabled set so we * can initialize the database. fipsenabled is similar. If * any of the servers have it set, they all will need to use * FIPS mode. */ if (sc->enabled == UNSET) { sc->enabled = FALSE; } if (sc->proxy_enabled == UNSET) { sc->proxy_enabled = FALSE; } if ((sc->enabled == TRUE) || (sc->proxy_enabled == TRUE)) { sslenabled = TRUE; } if (sc->fips == TRUE) { fipsenabled = TRUE; } } if (sslenabled == FALSE) { return OK; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Init: %snitializing NSS library", mc->nInitCount == 1 ? "I" : "Re-i"); /* The first pass through this function will create the semaphore that * will be used to lock the pipe. The user is still root at that point * so for any later calls the semaphore ops will fail with permission * errors. So switch the user to the Apache user. */ if (mc->semid) { uid_t user_id; user_id = ap_uname2id(mc->user); semctl(mc->semid, 0, IPC_STAT, &status); status.sem_perm.uid = user_id; semctl(mc->semid,0,IPC_SET,&status); } /* Do we need to fire up our password helper? */ if (mc->nInitCount == 1) { const char * child_argv[6]; apr_status_t rv; struct sembuf sb; char sembuf[32]; if (mc->pphrase_dialog_helper == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "NSSPassPhraseHelper is not set. It is required."); nss_die(); } mc->semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0600); if (mc->semid == -1) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Unable to obtain semaphore."); nss_die(); } /* Initialize the semaphore */ sb.sem_num = 0; sb.sem_op = 1; sb.sem_flg = 0; if ((semop(mc->semid, &sb, 1)) == -1) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Unable to initialize semaphore."); nss_die(); } PR_snprintf(sembuf, 32, "%d", mc->semid); child_argv[0] = mc->pphrase_dialog_helper; child_argv[1] = sembuf; child_argv[2] = fipsenabled ? "on" : "off"; child_argv[3] = mc->pCertificateDatabase; child_argv[4] = mc->pDBPrefix; child_argv[5] = NULL; rv = apr_procattr_create(&mc->procattr, mc->pPool); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "apr_procattr_create() failed APR err: %d.", rv); nss_die(); } apr_procattr_io_set(mc->procattr, APR_PARENT_BLOCK, APR_PARENT_BLOCK, APR_FULL_NONBLOCK); apr_procattr_error_check_set(mc->procattr, 1); /* the process inherits our environment, which should allow the * dynamic loader to find NSPR and NSS. */ apr_procattr_cmdtype_set(mc->procattr, APR_PROGRAM_ENV); /* We've now spawned our helper process, the actual communication * with it occurs in nss_engine_pphrase.c. */ rv = apr_proc_create(&mc->proc, child_argv[0], child_argv, NULL, mc->procattr, mc->pPool); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "apr_proc_create failed to launch %s APR err: %d.", child_argv[0], rv); nss_die(); } /* Set a 30-second read/write timeout */ apr_file_pipe_timeout_set(mc->proc.in, apr_time_from_sec(30)); apr_file_pipe_timeout_set(mc->proc.out, apr_time_from_sec(30)); } /* Initialize NSPR */ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); /* Set the PKCS #11 string for the internal token to a nicer name. */ PK11_ConfigurePKCS11(NULL,NULL,NULL, INTERNAL_TOKEN_NAME, NULL, NULL,NULL,NULL,8,1); ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, "Initializing SSL Session Cache of size %d. SSL3/TLS timeout = %d.", mc->session_cache_size, mc->ssl3_session_cache_timeout); ap_mpm_query(AP_MPMQ_MAX_THREADS, &threaded); if (!threaded) SSL_ConfigMPServerSIDCache(mc->session_cache_size, (PRUint32) mc->session_cache_timeout, (PRUint32) mc->ssl3_session_cache_timeout, NULL); else SSL_ConfigServerSessionIDCache(mc->session_cache_size, (PRUint32) mc->session_cache_timeout, (PRUint32) mc->ssl3_session_cache_timeout, NULL); /* Load our layer */ nss_io_layer_init(); if (mc->nInitCount == 1) { nss_init_SSLLibrary(base_server, mc->pPool); /* * initialize servers */ ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, "Init: Initializing (virtual) servers for SSL"); CERTCertList* clist = PK11_ListCerts(PK11CertListUserUnique, NULL); for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); /* * Either now skip this server when SSL is disabled for * it or give out some information about what we're * configuring. */ /* * Read the server certificate and key */ nss_init_ConfigureServer(s, p, ptemp, sc, clist); } if (clist) { CERT_DestroyCertList(clist); } } /* * Announce mod_nss and SSL library in HTTP Server field * as ``mod_nss/X.X.X NSS/X.X.X'' */ nss_add_version_components(p, base_server); return OK; } static void nss_init_ctx_socket(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx) { /* Setup a socket in the context that will be used to model all * client connections. */ mctx->model = nss_io_new_fd(); mctx->model = SSL_ImportFD(NULL, mctx->model); if (SSL_OptionSet(mctx->model, SSL_SECURITY, PR_TRUE) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Unable to enable security."); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } if (SSL_OptionSet(mctx->model, SSL_HANDSHAKE_AS_SERVER, mctx->as_server) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Unable to set SSL server handshake mode."); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } if (SSL_OptionSet(mctx->model, SSL_HANDSHAKE_AS_CLIENT, !mctx->as_server) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Unable to set handshake as client"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } if (!mctx->as_server) { if ((SSL_OptionSet(mctx->model, SSL_NO_CACHE, PR_TRUE)) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Unable to disable SSL client caching"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } } #ifdef SSL_ENABLE_RENEGOTIATION if (SSL_OptionSet(mctx->model, SSL_ENABLE_RENEGOTIATION, mctx->enablerenegotiation ? SSL_RENEGOTIATE_REQUIRES_XTN : SSL_RENEGOTIATE_NEVER ) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Unable to set SSL renegotiation"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } if (SSL_OptionSet(mctx->model, SSL_REQUIRE_SAFE_NEGOTIATION, mctx->requiresafenegotiation) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Unable to set SSL safe negotiation"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } #endif } static void nss_init_ctx_protocol(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx) { int ssl3, tls, tls1_1, tls1_2; char *protocol_marker = NULL; char *lprotocols = NULL; SECStatus stat; SSLVersionRange enabledVersions; ssl3 = tls = tls1_1 = tls1_2 = 0; /* * Since this routine will be invoked individually for every thread * associated with each 'server' object as well as for every thread * associated with each 'proxy' object, identify the protocol marker * ('NSSProtocol' for 'server' versus 'NSSProxyProtocol' for 'proxy') * via each thread's object type and apply this useful information to * all log messages. */ if (mctx == mctx->sc->server) { protocol_marker = "NSSProtocol"; } else if (mctx == mctx->sc->proxy) { protocol_marker = "NSSProxyProtocol"; } if (mctx->sc->fips) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "In FIPS mode ignoring %s list, enabling TLSv1.0, TLSv1.1 and TLSv1.2", protocol_marker); tls = tls1_1 = tls1_2 = 1; } else { if (mctx->auth.protocols == NULL) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "%s value not set; using: TLSv1.0, TLSv1.1 and TLSv1.2", protocol_marker); tls = tls1_1 = tls1_2 = 1; } else { lprotocols = strdup(mctx->auth.protocols); ap_str_tolower(lprotocols); if (strstr(lprotocols, "all") != NULL) { ssl3 = tls = tls1_1 = tls1_2 = 1; } else { char *protocol_list = NULL; char *saveptr = NULL; char *token = NULL; for (protocol_list = lprotocols; ; protocol_list = NULL) { token = strtok_r(protocol_list, ",", &saveptr); if (token == NULL) { break; } else if (strcmp(token, "sslv2") == 0) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "%s: SSL2 is not supported", protocol_marker); } else if (strcmp(token, "sslv3") == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: Enabling SSL3", protocol_marker); ssl3 = 1; } else if (strcmp(token, "tlsv1") == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: Enabling TLSv1.0 via TLSv1", protocol_marker); ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "%s: The 'TLSv1' protocol name has been deprecated; please change 'TLSv1' to 'TLSv1.0'.", protocol_marker); tls = 1; } else if (strcmp(token, "tlsv1.0") == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: Enabling TLSv1.0", protocol_marker); tls = 1; } else if (strcmp(token, "tlsv1.1") == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: Enabling TLSv1.1", protocol_marker); tls1_1 = 1; } else if (strcmp(token, "tlsv1.2") == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: Enabling TLSv1.2", protocol_marker); tls1_2 = 1; } else { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "%s: Unknown protocol '%s' not supported", protocol_marker, token); } } } free(lprotocols); } } stat = SECSuccess; stat = SSL_OptionSet(mctx->model, SSL_ENABLE_SSL2, PR_FALSE); /* Set protocol version ranges: * * (1) Set the minimum protocol accepted * (2) Set the maximum protocol accepted * (3) Protocol ranges extend from maximum down to minimum protocol * (4) All protocol ranges are completely inclusive; * no protocol in the middle of a range may be excluded * (5) NSS automatically negotiates the use of the strongest protocol * for a connection starting with the maximum specified protocol * and downgrading as necessary to the minimum specified protocol * * For example, if SSL 3.0 is chosen as the minimum protocol, and * TLS 1.1 is chosen as the maximum protocol, SSL 3.0, TLS 1.0, and * TLS 1.1 will all be accepted as protocols, as TLS 1.0 will not and * cannot be excluded from this range. NSS will automatically negotiate * to utilize the strongest acceptable protocol for a connection starting * with the maximum specified protocol and downgrading as necessary to the * minimum specified protocol (TLS 1.2 -> TLS 1.1 -> TLS 1.0 -> SSL 3.0). */ if (stat == SECSuccess) { /* Set minimum protocol version (lowest -> highest) * * SSL 3.0 -> TLS 1.0 -> TLS 1.1 -> TLS 1.2 */ if (ssl3 == 1) { enabledVersions.min = SSL_LIBRARY_VERSION_3_0; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [SSL 3.0] (minimum)", protocol_marker); } else if (tls == 1) { enabledVersions.min = SSL_LIBRARY_VERSION_TLS_1_0; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.0] (minimum)", protocol_marker); } else if (tls1_1 == 1) { enabledVersions.min = SSL_LIBRARY_VERSION_TLS_1_1; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.1] (minimum)", protocol_marker); } else if (tls1_2 == 1) { enabledVersions.min = SSL_LIBRARY_VERSION_TLS_1_2; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.2] (minimum)", protocol_marker); } else { /* Set default minimum protocol version to SSL 3.0 */ enabledVersions.min = SSL_LIBRARY_VERSION_3_0; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [SSL 3.0] (default minimum)", protocol_marker); } /* Set maximum protocol version (highest -> lowest) * * TLS 1.2 -> TLS 1.1 -> TLS 1.0 -> SSL 3.0 */ if (tls1_2 == 1) { enabledVersions.max = SSL_LIBRARY_VERSION_TLS_1_2; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.2] (maximum)", protocol_marker); } else if (tls1_1 == 1) { enabledVersions.max = SSL_LIBRARY_VERSION_TLS_1_1; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.1] (maximum)", protocol_marker); } else if (tls == 1) { enabledVersions.max = SSL_LIBRARY_VERSION_TLS_1_0; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.0] (maximum)", protocol_marker); } else if (ssl3 == 1) { enabledVersions.max = SSL_LIBRARY_VERSION_3_0; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [SSL 3.0] (maximum)", protocol_marker); } else { /* Set default maximum protocol version to TLS 1.2 */ enabledVersions.max = SSL_LIBRARY_VERSION_TLS_1_2; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: [TLS 1.2] (default maximum)", protocol_marker); } stat = SSL_VersionRangeSet(mctx->model, &enabledVersions); } if (stat != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "%s: SSL/TLS protocol initialization failed.", protocol_marker); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } mctx->ssl3 = ssl3; mctx->tls = tls || tls1_1 || tls1_2; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%sabling TLS Session Tickets", mctx->sc->session_tickets == PR_TRUE ? "En" : "Dis"); if (SSL_OptionSet(mctx->model, SSL_ENABLE_SESSION_TICKETS, mctx->sc->session_tickets) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Unable to configure TLS Session Tickets"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } } static void nss_init_ctx_session_cache(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx) { } static void nss_init_ctx_callbacks(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx) { if (SSL_AuthCertificateHook(mctx->model, nss_AuthCertificate, (void *)CERT_GetDefaultCertDB()) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SSL_AuthCertificateHook failed."); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } if (SSL_BadCertHook(mctx->model, (SSLBadCertHandler) ownBadCertHandler, NULL) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SSL_BadCertHook failed"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } if (SSL_HandshakeCallback(mctx->model, (SSLHandshakeCallback) ownHandshakeCallback, NULL) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SSL_HandshakeCallback failed"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } if (SSL_GetClientAuthDataHook(mctx->model, NSS_GetClientAuthData, (void *)mctx->nickname) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SSL_GetClientAuthDataHook failed"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } } static void nss_init_ctx_verify(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx) { if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) { SSL_OptionSet(mctx->model, SSL_REQUEST_CERTIFICATE, PR_TRUE); SSL_OptionSet(mctx->model, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS); } else if (mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL) { SSL_OptionSet(mctx->model, SSL_REQUEST_CERTIFICATE, PR_TRUE); SSL_OptionSet(mctx->model, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER); } else { SSL_OptionSet(mctx->model, SSL_REQUEST_CERTIFICATE, PR_FALSE); SSL_OptionSet(mctx->model, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER); } } static void nss_init_ctx_cipher_suite(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx) { PRBool cipher_state[ciphernum]; PRBool fips_state[ciphernum]; const char *suite = mctx->auth.cipher_suite; char * object_type = NULL; char * cipher_suite_marker = NULL; char * ciphers; char * fipsciphers = NULL; int i; /* * Configure SSL Cipher Suite */ if (!suite) { /* * Since this is a 'fatal' error, regardless of whether this * particular invocation is from a 'server' object or a 'proxy' * object, issue all error message(s) as appropriate. */ if ((mctx->sc->enabled == TRUE) && (mctx->sc->server) && (!mctx->sc->server->auth.cipher_suite)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "NSSEngine on; required value NSSCipherSuite not set."); } if ((mctx->sc->proxy_enabled == TRUE) && (mctx->sc->proxy) && (!mctx->sc->proxy->auth.cipher_suite)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "NSSProxyEngine on; required value NSSProxyCipherSuite not set."); } nss_die(); } /* * Since this routine will be invoked individually for every thread * associated with each 'server' object as well as for every thread * associated with each 'proxy' object, identify the cipher suite markers * ('NSSCipherSuite' for 'server' versus 'NSSProxyCipherSuite' for 'proxy') * via each thread's object type and apply this useful information to * all log messages. */ if (mctx == mctx->sc->server) { object_type = "server"; cipher_suite_marker = "NSSCipherSuite"; } else if (mctx == mctx->sc->proxy) { object_type = "proxy"; cipher_suite_marker = "NSSProxyCipherSuite"; } ciphers = strdup(suite); #define CIPHERSIZE 2048 if (mctx->sc->fips) { SSLCipherSuiteInfo suite; int i; int nfound = 0; fipsciphers = (char *)malloc(CIPHERSIZE); fipsciphers[0] = '\0'; for (i=0; i 0) { fipsciphers[strlen(fipsciphers) - 1] = '\0'; /* remove last comma */ } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "FIPS mode enabled on this %s, permitted SSL ciphers are: [%s]", object_type, fipsciphers); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s: Configuring permitted SSL ciphers [%s]", cipher_suite_marker, suite); /* Disable all NSS supported cipher suites. This is to prevent any new * NSS cipher suites from getting automatically and unintentionally * enabled as a result of the NSS_SetDomesticPolicy() call. This way, * only the ciphers explicitly specified in the server configuration can * ever be enabled. */ for (i = 0; i < SSL_NumImplementedCiphers; i++) { SSL_CipherPrefSet(mctx->model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED); } /* initialize all known ciphers to false */ for (i=0; isc->fips) { if (nss_parse_ciphers(s, fipsciphers, fips_state) == -1) { nss_die(); } } free(ciphers); free(fipsciphers); /* If FIPS is enabled, see if any non-FIPS ciphers were selected */ if (mctx->sc->fips) { for (i=0; issl3 && countciphers(cipher_state, SSLV3) == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "%s: SSL3 is enabled but no SSL3 ciphers are enabled.", cipher_suite_marker); nss_die(); } if (mctx->tls && countciphers(cipher_state, TLSV1|TLSV1_2) == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "%s: TLS is enabled but no TLS ciphers are enabled.", cipher_suite_marker); nss_die(); } /* Finally actually enable the selected ciphers */ for (i=0; imodel, ciphers_def[i].num, cipher_state[i] == 1 ? PR_TRUE : PR_FALSE); } } static void nss_init_server_check(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx) { #ifdef NSS_ENABLE_ECC if (mctx->servercert != NULL || mctx->eccservercert != NULL) { #else if (mctx->servercert != NULL) { #endif ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Illegal attempt to re-initialise SSL for server " "(theoretically shouldn't happen!)"); nss_die(); } } static void nss_init_ctx(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx) { nss_init_ctx_socket(s, p, ptemp, mctx); nss_init_ctx_protocol(s, p, ptemp, mctx); nss_init_ctx_session_cache(s, p, ptemp, mctx); nss_init_ctx_callbacks(s, p, ptemp, mctx); nss_init_ctx_verify(s, p, ptemp, mctx); nss_init_ctx_cipher_suite(s, p, ptemp, mctx); } static void nss_init_certificate(server_rec *s, const char *nickname, CERTCertificate **servercert, SECKEYPrivateKey **serverkey, SSLKEAType *KEAtype, PRFileDesc *model, int enforce, int sni, const CERTCertList* clist) { SECCertTimeValidity certtimestatus; SECStatus secstatus; PK11SlotInfo* slot = NULL; CERTCertNicknames *certNickDNS = NULL; char **nnptr = NULL; int nn = 0; apr_array_header_t *names = NULL; apr_array_header_t *wild_names = NULL; int i, j; if (nickname == NULL) { return; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Using nickname %s.", nickname); *servercert = FindServerCertFromNickname(nickname, clist); /* Verify the certificate chain. */ if (*servercert != NULL) { SECCertificateUsage usage = certificateUsageSSLServer; if (enforce) { if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), *servercert, PR_TRUE, usage, NULL, NULL) != SECSuccess) { nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Unable to verify certificate '%s'. Add \"NSSEnforceValidCerts off\" to nss.conf so the server can start until the problem can be resolved.", nickname); nss_die(); } } } else { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Certificate not found: '%s'", nickname); nss_die(); } if (strchr(nickname, ':')) { char* token = strdup(nickname); char* colon = strchr(token, ':'); if (colon) { *colon = 0; slot = PK11_FindSlotByName(token); if (!slot) { /* * Slot not found. This should never happen because we * already found the cert. */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Slot not found"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); free(token); nss_die(); } } free(token); } else { slot = PK11_GetInternalKeySlot(); } *serverkey = PK11_FindPrivateKeyFromCert(slot, *servercert, NULL); PK11_FreeSlot(slot); if (*serverkey == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Key not found for: '%s'", nickname); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } *KEAtype = NSS_FindCertKEAType(*servercert); /* add ServerAlias entries to hash */ names = s->names; if (names) { char **name = (char **)names->elts; for (i = 0; i < names->nelts; ++i) { ap_str_tolower(name[i]); addHashVhostNick(name[i], (char *)nickname); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SNI ServerAlias: %s -> %s", name[i], nickname); } } /* add ServerAlias entries with wildcards */ wild_names = s->wild_names; if (wild_names) { char **wild_name = (char **)wild_names->elts; for (j = 0; j < wild_names->nelts; ++j) { ap_str_tolower(wild_name[j]); addHashVhostNick(wild_name[j], (char *)nickname); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SNI wildcard: %s -> %s", wild_name[j], nickname); } } /* get valid DNS names from certificate to hash */ certNickDNS = CERT_GetValidDNSPatternsFromCert(*servercert); if (certNickDNS) { nnptr = certNickDNS->nicknames; nn = certNickDNS->numnicknames; while ( nn > 0 ) { ap_str_tolower(*nnptr); addHashVhostNick(*nnptr, (char *)nickname); nnptr++; nn--; } PORT_FreeArena(certNickDNS->arena, PR_FALSE); } /* Subject/hostname check */ secstatus = CERT_VerifyCertName(*servercert, s->server_hostname); if (secstatus != SECSuccess) { char *cert_dns = CERT_GetCommonName(&(*servercert)->subject); ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Misconfiguration of certificate's CN and virtual name." " The certificate CN has %s. We expected %s as virtual" " name.", cert_dns, s->server_hostname); PORT_Free(cert_dns); } /* * Check for certs that are expired or not yet valid and WARN about it. * No need to refuse working - the client gets a warning. */ certtimestatus = CERT_CheckCertValidTimes(*servercert, PR_Now(), PR_FALSE); switch (certtimestatus) { case secCertTimeValid: /* ok */ break; case secCertTimeExpired: ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Server certificate is expired: '%s'", nickname); break; case secCertTimeNotValidYet: ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Certificate is not valid yet '%s'", nickname); default: ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Unhandled Certificate time type %d for: '%s'", certtimestatus, nickname); break; } secstatus = SSL_ConfigSecureServer(model, *servercert, *serverkey, *KEAtype); if (secstatus != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSL error configuring server: '%s'", nickname); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } if (PR_TRUE == sni) { if (SSL_SNISocketConfigHook(model, (SSLSNISocketConfig) nssSSLSNISocketConfig, (void*) s) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SSL_SNISocketConfigHook failed"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } } } static void nss_init_server_certs(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modnss_ctx_t *mctx, const CERTCertList* clist) { SECStatus secstatus; /* * Get own certificate and private key. */ if (mctx->as_server) { #ifdef NSS_ENABLE_ECC if (mctx->nickname == NULL && mctx->eccnickname == NULL) #else if (mctx->nickname == NULL) #endif { /* * Since this is a 'fatal' error, regardless of whether this * particular invocation is from a 'server' object or a 'proxy' * object, issue all error message(s) as appropriate. */ if ((mctx->sc->enabled == TRUE) && (mctx->sc->server) && (mctx->sc->server->nickname == NULL)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "NSSEngine on; no certificate nickname provided by NSSNickname."); } if ((mctx->sc->proxy_enabled == TRUE) && (mctx->sc->proxy) && (mctx->sc->proxy->nickname == NULL)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "NSSProxyEngine on; no certificate nickname provided by NSSProxyNickname."); } nss_die(); } nss_init_certificate(s, mctx->nickname, &mctx->servercert, &mctx->serverkey, &mctx->serverKEAType, mctx->model, mctx->enforce, mctx->sc->sni, clist); #ifdef NSS_ENABLE_ECC nss_init_certificate(s, mctx->eccnickname, &mctx->eccservercert, &mctx->eccserverkey, &mctx->eccserverKEAType, mctx->model, mctx->enforce, mctx->sc->sni, clist); #endif } secstatus = (SECStatus)SSL_SetPKCS11PinArg(mctx->model, NULL); if (secstatus != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Error setting PKCS11 pin argument: '%s'", mctx->nickname); nss_die(); } secstatus = (SECStatus)SSL_HandshakeCallback(mctx->model, (SSLHandshakeCallback)NSSHandshakeCallback, NULL); if (secstatus != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSL error configuring handshake callback: '%s'", mctx->nickname); nss_log_nss_error(APLOG_MARK, APLOG_ERR, s); nss_die(); } } static void nss_init_proxy_ctx(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, SSLSrvConfigRec *sc, const CERTCertList* clist) { nss_init_ctx(s, p, ptemp, sc->proxy); nss_init_server_certs(s, p, ptemp, sc->proxy, clist); } static void nss_init_server_ctx(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, SSLSrvConfigRec *sc, const CERTCertList* clist) { nss_init_server_check(s, p, ptemp, sc->server); nss_init_ctx(s, p, ptemp, sc->server); nss_init_server_certs(s, p, ptemp, sc->server, clist); } /* * Configure a particular server */ void nss_init_ConfigureServer(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, SSLSrvConfigRec *sc, const CERTCertList* clist) { if (sc->enabled == TRUE) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Configuring server for SSL protocol"); nss_init_server_ctx(s, p, ptemp, sc, clist); } if (sc->proxy_enabled == TRUE) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "Enabling proxy."); nss_init_proxy_ctx(s, p, ptemp, sc, clist); } } void nss_init_Child(apr_pool_t *p, server_rec *base_server) { SSLModConfigRec *mc = myModConfig(base_server); SSLSrvConfigRec *sc; server_rec *s; int threaded = 0; int sslenabled = FALSE; mc->pid = getpid(); /* only call getpid() once per-process */ /* * First, see if ssl is enabled at all */ for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); /* If any servers have SSL, we want sslenabled set so we * can perform further initialization */ if (sc->enabled == UNSET) { sc->enabled = FALSE; } if (sc->proxy_enabled == UNSET) { sc->proxy_enabled = FALSE; } if ((sc->enabled == TRUE) || (sc->proxy_enabled == TRUE)) { sslenabled = TRUE; } } if (sslenabled == FALSE) { /* we are not an SSL/TLS server */ return; } ap_mpm_query(AP_MPMQ_MAX_THREADS, &threaded); if (!threaded) { if (SSL_InheritMPServerSIDCache(NULL) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "SSL_InheritMPServerSIDCache failed"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, NULL); } } nss_init_SSLLibrary(base_server, mc->pPool); /* Configure all virtual servers */ CERTCertList* clist = PK11_ListCerts(PK11CertListUserUnique, NULL); for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); if (sc->server->servercert == NULL && NSS_IsInitialized()) { nss_init_ConfigureServer(s, p, mc->ptemp, sc, clist); } } if (clist) { CERT_DestroyCertList(clist); } /* * Let us cleanup on restarts and exits */ apr_pool_cleanup_register(p, base_server, nss_init_ChildKill, apr_pool_cleanup_null); } apr_status_t nss_init_ModuleKill(void *data) { server_rec *base_server = (server_rec *)data; SSLModConfigRec *mc = myModConfig(base_server); if (!NSS_IsInitialized()) { return APR_SUCCESS; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, "Shutting down SSL Session ID Cache"); SSL_ShutdownServerSessionIDCache(); if (mc->nInitCount == 1) nss_init_ChildKill(base_server); if (mp) { apr_pool_destroy(mp); mp = NULL; } /* NSS_Shutdown() gets called in nss_init_ChildKill */ return APR_SUCCESS; } apr_status_t nss_init_ChildKill(void *data) { SSLSrvConfigRec *sc; server_rec *base_server = (server_rec *)data; server_rec *s; int shutdown = 0; /* * Free the non-pool allocated structures * in the per-server configurations */ for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); if (sc->enabled == TRUE) { if (sc->server->nickname) { CERT_DestroyCertificate(sc->server->servercert); SECKEY_DestroyPrivateKey(sc->server->serverkey); } #ifdef NSS_ENABLE_ECC if (sc->server->eccnickname) { CERT_DestroyCertificate(sc->server->eccservercert); SECKEY_DestroyPrivateKey(sc->server->eccserverkey); } #endif /* Closing this implicitly cleans up the copy of the certificates * and keys associated with any SSL socket */ if (sc->server->model) PR_Close(sc->server->model); shutdown = 1; } if (sc->proxy_enabled) { if (sc->proxy->servercert != NULL) { CERT_DestroyCertificate(sc->proxy->servercert); SECKEY_DestroyPrivateKey(sc->proxy->serverkey); } /* Closing this implicitly cleans up the copy of the certificates * and keys associated with any SSL socket */ if (sc->proxy->model) PR_Close(sc->proxy->model); shutdown = 1; } } if (mp) { apr_pool_destroy(mp); mp = NULL; } if (shutdown) { /* Clear any client-side session cache data */ SSL_ClearSessionCache(); if (CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB()) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Turning off the OCSP default responder failed."); nss_log_nss_error(APLOG_MARK, APLOG_ERR, NULL); } NSS_Shutdown(); } return APR_SUCCESS; } /* * This callback is used when the incoming cert is not valid. * It should return SECSuccess to accept the cert anyway, SECFailure * to reject. In this case we always reject. */ SECStatus ownBadCertHandler(void *arg, PRFileDesc * socket) { PRErrorCode err = PR_GetError(); switch (err) { default: ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Bad remote server certificate: %d", err); nss_log_nss_error(APLOG_MARK, APLOG_ERR, NULL); return SECFailure; break; } } /* * Called by SSL to inform application that the handshake is * complete. This function is mostly used on the server side of an SSL * connection, although it is provided for a client as well. * We don't do anything special. */ SECStatus ownHandshakeCallback(PRFileDesc * socket, void *arg) { return SECSuccess; } /* * Duplicated, non-exported function from NSS that compares 2 certificate * times. */ static PRBool cert_IsNewer(CERTCertificate *certa, CERTCertificate *certb) { PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now; SECStatus rv; PRBool newerbefore, newerafter; newerbefore = newerafter = PR_FALSE; rv = CERT_GetCertTimes(certa, ¬BeforeA, ¬AfterA); if ( rv != SECSuccess ) { return(PR_FALSE); } rv = CERT_GetCertTimes(certb, ¬BeforeB, ¬AfterB); if ( rv != SECSuccess ) { return(PR_TRUE); } if ( LL_CMP(notBeforeA, >, notBeforeB) ) { newerbefore = PR_TRUE; } if ( LL_CMP(notAfterA, >, notAfterB) ) { newerafter = PR_TRUE; } if ( newerbefore && newerafter ) { return(PR_TRUE); } if ( ( !newerbefore ) && ( !newerafter ) ) { return(PR_FALSE); } /* get current UTC time */ now = PR_Now(); if ( newerbefore ) { /* cert A was issued after cert B, but expires sooner */ /* if A is expired, then pick B */ if ( LL_CMP(notAfterA, <, now ) ) { return(PR_FALSE); } return(PR_TRUE); } else { /* cert B was issued after cert A, but expires sooner */ /* if B is expired, then pick A */ if ( LL_CMP(notAfterB, <, now ) ) { return(PR_TRUE); } return(PR_FALSE); } } /* * Given a nickname, find the "best" certificate available for that * certificate (for the case of multiple CN's with different usages, a * renewed cert that is not yet valid, etc). The best is defined as the * newest, valid server certificate. */ static CERTCertificate* FindServerCertFromNickname(const char* name, const CERTCertList* clist) { CERTCertificate* bestcert = NULL; CERTCertListNode *cln; PRUint32 bestCertMatchedUsage = 0; PRBool bestCertIsValid = PR_FALSE; if (name == NULL) return NULL; for (cln = CERT_LIST_HEAD(clist); !CERT_LIST_END(cln,clist); cln = CERT_LIST_NEXT(cln)) { CERTCertificate* cert = cln->cert; const char* nickname = (const char*) cln->appData; if (!nickname) { nickname = cert->nickname; } if (strcmp(name, nickname) == 0) { PRUint32 matchedUsage = 0; PRBool isValid = PR_FALSE; PRBool swapcert = PR_FALSE; /* We still need to check key usage. Dual-key certs appear * as 2 certs in the list with different usages. We want to pick * the "best" one, preferrably the one with certUsageSSLServer. * Otherwise just return the cert if the nickname matches. */ if (CERT_CheckCertUsage(cert, certUsageSSLServer) == SECSuccess) { matchedUsage = 2; } else { if (CERT_CheckCertUsage(cert, certUsageEmailRecipient) == SECSuccess) { matchedUsage = 1; } } if (secCertTimeValid == CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE)) { /* This is a valid certificate. */ isValid = PR_TRUE; } if (!bestcert) { /* We didn't have a cert picked yet, automatically choose this * one. */ swapcert = PR_TRUE; } else { if (matchedUsage > bestCertMatchedUsage) { /* The cert previously picked didn't have the correct * usage, but this one does. Choose this one. */ swapcert = PR_TRUE; } else { if ( (bestCertMatchedUsage == matchedUsage) && (((PR_FALSE == bestCertIsValid) && (PR_TRUE == isValid)) || ((PR_TRUE == bestCertIsValid == isValid) && (PR_TRUE == cert_IsNewer(cert, bestcert))))) { /* The cert previously picked was invalid but this one * is. Or they were both valid but this one is newer. */ swapcert = PR_TRUE; } } } if (swapcert == PR_TRUE) { bestcert = cert; bestCertMatchedUsage = matchedUsage; bestCertIsValid = isValid; } } } if (bestcert) { bestcert = CERT_DupCertificate(bestcert); } return bestcert; } /* * Executed automatically when the SSL handshake is completed. * We don't do anything special here. */ SECStatus NSSHandshakeCallback(PRFileDesc *socket, void *arg) { return SECSuccess; } /* * Callback made during SSL request to see if SNI was requested and * pair it with a configured nickname. */ PRInt32 nssSSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr, PRUint32 sniNameArrSize, void *arg) { server_rec *s = (server_rec *)arg; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "nssSSLSNISocketConfig"); void *pinArg; CERTCertificate *cert = NULL; SECKEYPrivateKey *privKey = NULL; char *nickName = NULL; char *vhost = NULL; apr_pool_t *str_p; PORT_Assert(fd && sniNameArr); if (!fd || !sniNameArr) { return SSL_SNI_SEND_ALERT; } apr_pool_create(&str_p, NULL); vhost = apr_pstrndup(str_p, (char *) sniNameArr->data, sniNameArr->len); /* rfc6125 - Checking of Traditional Domain Names */ ap_str_tolower(vhost); nickName = searchHashVhostbyNick(vhost); if (nickName == NULL) { /* search for wildcard_names in serverAlises */ nickName = searchHashVhostbyNick_match(vhost); if (nickName == NULL) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SNI: Search for %s failed. Unrecognized name.", vhost); goto loser; } } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,"SNI: Found nickname %s for vhost: %s", nickName, vhost); pinArg = SSL_RevealPinArg(fd); /* if pinArg is NULL, then we would not get the key and * return an error status. */ cert = PK11_FindCertFromNickname(nickName, &pinArg); if (cert == NULL) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Failed to find certificate for nickname: %s", nickName); goto loser; } privKey = PK11_FindKeyByAnyCert(cert, &pinArg); if (privKey == NULL) { goto loser; } SSLKEAType certKEA = NSS_FindCertKEAType(cert); if (SSL_ConfigSecureServer(fd, cert, privKey, certKEA) != SECSuccess) { goto loser; /* Send alert */ } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "SNI: Successfully paired vhost %s with nickname: %s", vhost, nickName); apr_pool_destroy(str_p); SECKEY_DestroyPrivateKey(privKey); CERT_DestroyCertificate(cert); return 0; loser: if (privKey) SECKEY_DestroyPrivateKey(privKey); if (cert) CERT_DestroyCertificate(cert); apr_pool_destroy(str_p); return SSL_SNI_SEND_ALERT; } mod_nss-1.0.12/nss_engine_io.c000066400000000000000000001336441260357105600162400ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" /* _________________________________________________________________ ** ** I/O Hooks ** _________________________________________________________________ */ /* This file is designed to be the bridge between OpenSSL and httpd. * However, we really don't expect anyone (let alone ourselves) to * remember what is in this file. So, first, a quick overview. * * In this file, you will find: * - nss_io_filter_input (Apache input filter) * - nss_io_filter_output (Apache output filter) * * - bio_filter_in_* (OpenSSL input filter) * - nspr_filter_out_* (OpenSSL output filter) * * The input chain is roughly: * * nss_io_filter_input->nss_io_input_read->SSL_read->... * ...->bio_filter_in_read->ap_get_brigade/next-httpd-filter * * In mortal terminology, we do the following: * - Receive a request for data to the SSL input filter * - Call a helper function once we know we should perform a read * - Call OpenSSL's SSL_read() * - SSL_read() will then call bio_filter_in_read * - bio_filter_in_read will then try to fetch data from the next httpd filter * - bio_filter_in_read will flatten that data and return it to SSL_read * - SSL_read will then decrypt the data * - nss_io_input_read will then receive decrypted data as a char* and * ensure that there were no read errors * - The char* is placed in a brigade and returned * * Since connection-level input filters in httpd need to be able to * handle AP_MODE_GETLINE calls (namely identifying LF-terminated strings), * nss_io_input_getline which will handle this special case. * * Due to AP_MODE_GETLINE and AP_MODE_SPECULATIVE, we may sometimes have * 'leftover' decoded data which must be setaside for the next read. That * is currently handled by the char_buffer_{read|write} functions. So, * nss_io_input_read may be able to fulfill reads without invoking * SSL_read(). * * Note that the filter context of nss_io_filter_input and bio_filter_in_* * are shared as bio_filter_in_ctx_t. * * Note that the filter is by choice limited to reading at most * AP_IOBUFSIZE (8192 bytes) per call. * */ /* Private structures */ typedef struct nspr_filter_in_ctx_t nspr_filter_in_ctx_t; typedef struct nspr_filter_out_ctx_t nspr_filter_out_ctx_t; typedef struct { PRFileDesc *pssl; conn_rec *c; ap_filter_t *pInputFilter; ap_filter_t *pOutputFilter; nspr_filter_in_ctx_t *inctx; nspr_filter_out_ctx_t *outctx; int nobuffer; /* non-zero to prevent buffering */ } nss_filter_ctx_t; typedef struct { int length; char *value; } char_buffer_t; struct nspr_filter_out_ctx_t { nss_filter_ctx_t *filter_ctx; apr_bucket_brigade *bb; apr_size_t length; char buffer[AP_IOBUFSIZE]; apr_size_t blen; apr_status_t rc; }; struct nspr_filter_in_ctx_t { ap_filter_t *f; apr_status_t rc; ap_input_mode_t mode; apr_read_type_e block; apr_bucket_brigade *bb; char_buffer_t cbuf; apr_pool_t *pool; char buffer[AP_IOBUFSIZE]; nss_filter_ctx_t *filter_ctx; }; /* Global variables for the NSPR I/O layer */ static PRDescIdentity gIdentity = PR_INVALID_IO_LAYER; static PRIOMethods gMethods; /* * this char_buffer api might seem silly, but we don't need to copy * any of this data and we need to remember the length. */ static int char_buffer_read(char_buffer_t *buffer, char *in, int inl) { if (!buffer->length) { return 0; } if (buffer->length > inl) { /* we have have enough to fill the caller's buffer */ memmove(in, buffer->value, inl); buffer->value += inl; buffer->length -= inl; } else { /* swallow remainder of the buffer */ memmove(in, buffer->value, buffer->length); inl = buffer->length; buffer->value = NULL; buffer->length = 0; } return inl; } static int char_buffer_write(char_buffer_t *buffer, char *in, int inl) { buffer->value = in; buffer->length = inl; return inl; } /* This function will read from a brigade and discard the read buckets as it * proceeds. It will read at most *len bytes. */ static apr_status_t brigade_consume(apr_bucket_brigade *bb, apr_read_type_e block, char *c, apr_size_t *len) { apr_size_t actual = 0; apr_status_t status = APR_SUCCESS; while (!APR_BRIGADE_EMPTY(bb)) { apr_bucket *b = APR_BRIGADE_FIRST(bb); const char *str; apr_size_t str_len; apr_size_t consume; /* Justin points out this is an http-ism that might * not fit if brigade_consume is added to APR. Perhaps * apr_bucket_read(eos_bucket) should return APR_EOF? * Then this becomes mainline instead of a one-off. */ if (APR_BUCKET_IS_EOS(b)) { status = APR_EOF; break; } /* The reason I'm not offering brigade_consume yet * across to apr-util is that the following call * illustrates how borked that API really is. For * this sort of case (caller provided buffer) it * would be much more trivial for apr_bucket_consume * to do all the work that follows, based on the * particular characteristics of the bucket we are * consuming here. */ status = apr_bucket_read(b, &str, &str_len, block); if (status != APR_SUCCESS) { if (APR_STATUS_IS_EOF(status)) { /* This stream bucket was consumed */ apr_bucket_delete(b); continue; } break; } if (str_len > 0) { /* Do not block once some data has been consumed */ block = APR_NONBLOCK_READ; /* Assure we don't overflow. */ consume = (str_len + actual > *len) ? *len - actual : str_len; memcpy(c, str, consume); c += consume; actual += consume; if (consume >= b->length) { /* This physical bucket was consumed */ apr_bucket_delete(b); } else { /* Only part of this physical bucket was consumed */ b->start += consume; b->length -= consume; } } else if (b->length == 0) { apr_bucket_delete(b); } /* This could probably be actual == *len, but be safe from stray * photons. */ if (actual >= *len) { break; } } *len = actual; return status; } /* * this is the function called by PR_Read() */ static PRInt32 PR_CALLBACK nspr_filter_in_read(PRFileDesc *fd, void *in, PRInt32 inlen) { apr_size_t inl = inlen; nss_filter_ctx_t *filter_ctx = (nss_filter_ctx_t *)(fd->secret); nspr_filter_in_ctx_t *inctx = filter_ctx->inctx; apr_read_type_e block = inctx->block; inctx->rc = APR_SUCCESS; /* mod_ssl catches this case, so should we. */ if (!in) return 0; if (!inctx->bb) { inctx->rc = APR_EOF; return -1; } if (APR_BRIGADE_EMPTY(inctx->bb)) { inctx->rc = ap_get_brigade(inctx->f->next, inctx->bb, AP_MODE_READBYTES, block, inl); /* Not a problem, there was simply no data ready yet. */ if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc) || (inctx->rc == APR_SUCCESS && APR_BRIGADE_EMPTY(inctx->bb))) { PR_SetError(PR_WOULD_BLOCK_ERROR, 0); return -1; } if (inctx->rc != APR_SUCCESS) { /* Unexpected errors discard the brigade */ apr_brigade_cleanup(inctx->bb); inctx->bb = NULL; return -1; } } inctx->rc = brigade_consume(inctx->bb, block, in, &inl); if (inctx->rc == APR_SUCCESS) { return (int)inl; } if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc)) { PR_SetError(PR_WOULD_BLOCK_ERROR, 0); return (int)inl; } /* Unexpected errors and APR_EOF clean out the brigade. * Subsequent calls will return APR_EOF. */ apr_brigade_cleanup(inctx->bb); inctx->bb = NULL; if (APR_STATUS_IS_EOF(inctx->rc) && inl) { /* Provide the results of this read pass, * without resetting the BIO retry_read flag */ return (int)inl; } return -1; } static apr_status_t nss_io_input_read(nspr_filter_in_ctx_t *inctx, char *buf, apr_size_t *len) { apr_size_t wanted = *len; apr_size_t bytes = 0; int rc; conn_rec *c = inctx->filter_ctx->c; *len = 0; /* If we have something leftover from last time, try that first. */ if ((bytes = char_buffer_read(&inctx->cbuf, buf, wanted))) { *len = bytes; if (inctx->mode == AP_MODE_SPECULATIVE) { /* We want to rollback this read. */ if (inctx->cbuf.length > 0) { inctx->cbuf.value -= bytes; inctx->cbuf.length += bytes; } else { char_buffer_write(&inctx->cbuf, buf, (int)bytes); } return APR_SUCCESS; } /* This could probably be *len == wanted, but be safe from stray * photons. */ if (*len >= wanted) { return APR_SUCCESS; } if (inctx->mode == AP_MODE_GETLINE) { if (memchr(buf, APR_ASCII_LF, *len)) { return APR_SUCCESS; } } else { /* Down to a nonblock pattern as we have some data already */ inctx->block = APR_NONBLOCK_READ; } } while (1) { if (!inctx->filter_ctx->pssl) { /* Ensure a non-zero error code is returned */ if (inctx->rc == APR_SUCCESS) { inctx->rc = APR_EGENERAL; } break; } PR_SetError(0, 0); rc = PR_Read(inctx->filter_ctx->pssl, buf + bytes, wanted - bytes); if (rc > 0) { *len += rc; if (inctx->mode == AP_MODE_SPECULATIVE) { /* We want to rollback this read. */ char_buffer_write(&inctx->cbuf, buf, rc); } return inctx->rc; } else if (rc == 0) { /* If EAGAIN, we will loop given a blocking read, * otherwise consider ourselves at EOF. */ if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc)) { /* Already read something, return APR_SUCCESS instead. * On win32 in particular, but perhaps on other kernels, * a blocking call isn't 'always' blocking. */ if (*len > 0) { inctx->rc = APR_SUCCESS; break; } if (inctx->block == APR_NONBLOCK_READ) { break; } } else { if (*len > 0) { inctx->rc = APR_SUCCESS; } else { inctx->rc = APR_EOF; } break; } } else /* (rc < 0) */ { int nss_err = PR_GetError(); if (nss_err == PR_WOULD_BLOCK_ERROR) { /* * If NSPR wants to read more, and we were nonblocking, * report as an EAGAIN. Otherwise loop, pulling more * data from network filter. * * (This is usually the case when the client forces an SSL * renegotation which is handled implicitly by NSS.) */ inctx->rc = APR_EAGAIN; if (*len > 0) { inctx->rc = APR_SUCCESS; break; } if (inctx->block == APR_NONBLOCK_READ) { break; } continue; /* Blocking and nothing yet? Try again. */ } else if (nss_err != 0) { if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc)) { /* Already read something, return APR_SUCCESS instead. */ if (*len > 0) { inctx->rc = APR_SUCCESS; break; } if (inctx->block == APR_NONBLOCK_READ) { break; } continue; /* Blocking and nothing yet? Try again. */ } else { ap_log_error(APLOG_MARK, APLOG_INFO, inctx->rc, c->base_server, "SSL input filter read failed."); if (inctx->rc == 0) nss_log_nss_error(APLOG_MARK, APLOG_ERR, c->base_server); } } if (inctx->rc == APR_SUCCESS) { inctx->rc = APR_EGENERAL; } break; } } return inctx->rc; } static apr_status_t nss_io_input_getline(nspr_filter_in_ctx_t *inctx, char *buf, apr_size_t *len) { const char *pos = NULL; apr_status_t status; apr_size_t tmplen = *len, buflen = *len, offset = 0; *len = 0; /* * in most cases we get all the headers on the first SSL_read. * however, in certain cases SSL_read will only get a partial * chunk of the headers, so we try to read until LF is seen. */ while (tmplen > 0) { status = nss_io_input_read(inctx, buf + offset, &tmplen); if (status != APR_SUCCESS) { return status; } *len += tmplen; if ((pos = memchr(buf, APR_ASCII_LF, *len))) { break; } offset += tmplen; tmplen = buflen - offset; } if (pos) { char *value; int length; apr_size_t bytes = pos - buf; bytes += 1; value = buf + bytes; length = *len - bytes; char_buffer_write(&inctx->cbuf, value, length); *len = bytes; } return APR_SUCCESS; } static apr_status_t nss_filter_write(ap_filter_t *f, const char *data, apr_size_t len) { nss_filter_ctx_t *filter_ctx = f->ctx; nspr_filter_out_ctx_t *outctx; int res; /* write SSL */ if (filter_ctx->pssl == NULL) { return APR_EGENERAL; } outctx = filter_ctx->outctx; res = PR_Write(filter_ctx->pssl, (char *)data, len); if (res < 0) { int nss_err = PR_GetError(); if (nss_err == PR_WOULD_BLOCK_ERROR) { /* * If NSS wants to write more, and we were nonblocking, * report as an EAGAIN. Otherwise loop, pushing more * data at the network filter. * * (This is usually the case when the client forces an SSL * renegotation which is handled implicitly by OpenSSL.) */ outctx->rc = APR_EAGAIN; } else { conn_rec *c = f->c; /* * Log SSL errors */ ap_log_error(APLOG_MARK, APLOG_INFO, outctx->rc, c->base_server, "SSL library error %d writing data", nss_err); nss_log_nss_error(APLOG_MARK, APLOG_INFO, c->base_server); } if (outctx->rc == APR_SUCCESS) { outctx->rc = APR_EGENERAL; } } else if ((apr_size_t)res != len) { conn_rec *c = f->c; char *reason = "reason unknown"; ap_log_error(APLOG_MARK, APLOG_INFO, outctx->rc, c->base_server, "failed to write %ld of %ld bytes (%s)", len - (apr_size_t)res, len, reason); outctx->rc = APR_EGENERAL; } return outctx->rc; } /* Just use a simple request. Any request will work for this, because * we use a flag in the conn_rec->conn_vector now. The fake request just * gets the request back to the Apache core so that a response can be sent. * * To avoid calling back for more data from the socket, use an HTTP/0.9 * request, and tack on an EOS bucket. */ #define HTTP_ON_HTTPS_PORT \ "GET /" CRLF #define HTTP_ON_HTTPS_PORT_BUCKET(alloc) \ apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \ sizeof(HTTP_ON_HTTPS_PORT) - 1, \ alloc) static void nss_io_filter_disable(SSLConnRec *sslconn, ap_filter_t *f) { nspr_filter_in_ctx_t *inctx = f->ctx; sslconn->ssl = NULL; inctx->filter_ctx->pssl = NULL; } static apr_status_t nss_io_filter_error(ap_filter_t *f, apr_bucket_brigade *bb, apr_status_t status) { SSLConnRec *sslconn = myConnConfig(f->c); apr_bucket *bucket; switch (status) { case HTTP_BAD_REQUEST: /* log the situation */ ap_log_error(APLOG_MARK, APLOG_INFO, 0, f->c->base_server, "SSL handshake failed: HTTP spoken on HTTPS port; " "trying to send HTML error page"); sslconn->non_nss_request = 1; nss_io_filter_disable(sslconn, f); /* fake the request line */ bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); break; default: return status; } APR_BRIGADE_INSERT_TAIL(bb, bucket); bucket = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bucket); return APR_SUCCESS; } static const char nss_io_filter[] = "NSS SSL/TLS Filter"; static const char nss_io_buffer[] = "NSS SSL/TLS Buffer"; static apr_status_t nss_filter_io_shutdown(nss_filter_ctx_t *filter_ctx, conn_rec *c, int abortive) { PRFileDesc *ssl = filter_ctx->pssl; SSLConnRec *sslconn = myConnConfig(c); if (!ssl) { return APR_SUCCESS; } PR_Shutdown(ssl, PR_SHUTDOWN_SEND); PR_Close(ssl); /* log the fact that we've closed the connection */ #if AP_SERVER_MINORVERSION_NUMBER <= 2 if (c->base_server->loglevel >= APLOG_INFO) { #else if (c->base_server->log.level >= APLOG_INFO) { #endif ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "Connection to child %ld closed " "(server %s, client %s)", c->id, nss_util_vhostid(c->pool, c->base_server), #if AP_SERVER_MINORVERSION_NUMBER <= 2 c->remote_ip ? c->remote_ip : "unknown"); #else c->client_ip ? c->client_ip : "unknown"); #endif } /* deallocate the SSL connection */ if (sslconn->client_cert) { CERT_DestroyCertificate(sslconn->client_cert); sslconn->client_cert = NULL; } sslconn->ssl = NULL; filter_ctx->pssl = NULL; /* so filters know we've been shutdown */ if (abortive) { /* prevent any further I/O */ c->aborted = 1; } return APR_SUCCESS; } static apr_status_t nss_io_filter_cleanup(void *data) { nss_filter_ctx_t *filter_ctx = data; if (filter_ctx->pssl) { conn_rec *c = filter_ctx->c; SSLConnRec *sslconn = myConnConfig(c); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SSL connection destroyed without being closed"); PR_Close(sslconn->ssl); sslconn->ssl = filter_ctx->pssl = NULL; } return APR_SUCCESS; } /* * This can't be done in a callback because of the way that mod_proxy * handles reuqests. It creates the connection, which for NSS * just generates a socket from the model, then it sets the proxy * hostname, then it writes the request. For NSS the writing of the * request is what generates the handshake but we don't have the * proxy hostname to set the SNI value for yet, so do it here. */ static apr_status_t nss_io_filter_handshake(ap_filter_t *f) { conn_rec *c = f->c; SSLConnRec *sslconn = myConnConfig(c); SECStatus rv; /* * Enable SNI for proxy backend requests. Make sure we don't do it for * pure SSLv3 connections, and also prevent IP addresses * from being included in the SNI extension. */ if (sslconn->is_proxy) { char *name = SSL_RevealURL(sslconn->ssl); const char *hostname_note; SSLChannelInfo channel; apr_ipsubnet_t *ip; if (name) { /* handshake is completed, SNI hostname already set */ PORT_Free(name); return APR_SUCCESS; } hostname_note = apr_table_get(c->notes, "proxy-request-hostname"); if ((hostname_note) && (SSL_GetChannelInfo(sslconn->ssl, &channel, sizeof channel) == SECSuccess) && (channel.protocolVersion != SSL_LIBRARY_VERSION_3_0) && apr_ipsubnet_create(&ip, hostname_note, NULL, c->pool) != APR_SUCCESS) { if ((rv = SSL_SetURL(sslconn->ssl, hostname_note)) != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "Error setting SNI extension for SSL Proxy request: %d", PR_GetError()); } else { ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "SNI extension for SSL Proxy request set to '%s'", hostname_note); } } else { ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "Can't set SNI extension: no hostname available"); } } return APR_SUCCESS; } static apr_status_t nss_io_filter_input(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { apr_status_t status; nspr_filter_in_ctx_t *inctx = f->ctx; apr_size_t len = sizeof(inctx->buffer); int is_init = (mode == AP_MODE_INIT); if (f->c->aborted) { /* XXX: Ok, if we aborted, we ARE at the EOS. We also have * aborted. This 'double protection' is probably redundant, * but also effective against just about anything. */ apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bucket); return APR_ECONNABORTED; } if (!inctx->filter_ctx->pssl) { return ap_get_brigade(f->next, bb, mode, block, readbytes); } /* XXX: we don't currently support anything other than these modes. */ if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE && mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) { return APR_ENOTIMPL; } inctx->mode = mode; inctx->block = block; if ((status = nss_io_filter_handshake(f)) != APR_SUCCESS) { return nss_io_filter_error(f, bb, status); } if (is_init) { /* protocol module needs to handshake before sending * data to client (e.g. NNTP or FTP) */ return APR_SUCCESS; } if (inctx->mode == AP_MODE_READBYTES || inctx->mode == AP_MODE_SPECULATIVE) { /* Protected from truncation, readbytes < MAX_SIZE_T * FIXME: No, it's *not* protected. -- jre */ if (readbytes < len) { len = (apr_size_t)readbytes; } status = nss_io_input_read(inctx, inctx->buffer, &len); } else if (inctx->mode == AP_MODE_GETLINE) { status = nss_io_input_getline(inctx, inctx->buffer, &len); } else { /* We have no idea what you are talking about, so return an error. */ return APR_ENOTIMPL; } if (status != APR_SUCCESS) { return nss_io_filter_error(f, bb, status); } /* Create a transient bucket out of the decrypted data. */ if (len > 0) { apr_bucket *bucket = apr_bucket_transient_create(inctx->buffer, len, f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bucket); } return APR_SUCCESS; } static int nspr_filter_out_flush(nspr_filter_out_ctx_t *outctx) { apr_bucket *e; if (!(outctx->blen || outctx->length)) { outctx->rc = APR_SUCCESS; return 1; } if (outctx->blen) { e = apr_bucket_transient_create(outctx->buffer, outctx->blen, outctx->bb->bucket_alloc); /* we filled this buffer first so add it to the * head of the brigade */ APR_BRIGADE_INSERT_HEAD(outctx->bb, e); outctx->blen = 0; } outctx->length = 0; e = apr_bucket_flush_create(outctx->bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(outctx->bb, e); outctx->rc = ap_pass_brigade(outctx->filter_ctx->pOutputFilter->next, outctx->bb); if (outctx->rc == APR_SUCCESS && outctx->filter_ctx->c->aborted) { outctx->rc = APR_ECONNRESET; } return (outctx->rc == APR_SUCCESS) ? 1 : -1; } static PRInt32 PR_CALLBACK nspr_filter_out_write(PRFileDesc *fd, const void *in, PRInt32 inl) { nss_filter_ctx_t *filter_ctx = (nss_filter_ctx_t *)(fd->secret); nspr_filter_out_ctx_t *outctx = filter_ctx->outctx; /* pass along the encrypted data * need to flush since we're using SSL's malloc-ed buffer * which will be overwritten once we leave here */ apr_bucket *bucket = apr_bucket_transient_create(in, inl, outctx->bb->bucket_alloc); outctx->length += inl; APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket); if (nspr_filter_out_flush(outctx) < 0) { return -1; } return inl; } static apr_status_t nss_io_filter_output(ap_filter_t *f, apr_bucket_brigade *bb) { apr_status_t status = APR_SUCCESS; nss_filter_ctx_t *filter_ctx = f->ctx; nspr_filter_in_ctx_t *inctx; nspr_filter_out_ctx_t *outctx; apr_read_type_e rblock = APR_NONBLOCK_READ; if (f->c->aborted) { apr_brigade_cleanup(bb); return APR_ECONNABORTED; } if (!filter_ctx->pssl) { /* nss_filter_io_shutdown was called */ return ap_pass_brigade(f->next, bb); } inctx = filter_ctx->inctx; outctx = filter_ctx->outctx; /* When we are the writer, we must initialize the inctx * mode so that we block for any required ssl input, because * output filtering is always nonblocking. */ inctx->mode = AP_MODE_READBYTES; inctx->block = APR_BLOCK_READ; if ((status = nss_io_filter_handshake(f)) != APR_SUCCESS) { return nss_io_filter_error(f, bb, status); } while (!APR_BRIGADE_EMPTY(bb)) { apr_bucket *bucket = APR_BRIGADE_FIRST(bb); /* If it is a flush or EOS, we need to pass this down. * These types do not require translation by OpenSSL. */ if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) { if (nspr_filter_out_flush(filter_ctx->outctx) < 0) { status = outctx->rc; break; } if (APR_BUCKET_IS_EOS(bucket)) { /* * By definition, nothing can come after EOS. * which also means we can pass the rest of this brigade * without creating a new one since it only contains the * EOS bucket. */ if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { return status; } break; } else { /* nspr_filter_out_flush() already passed down a flush bucket * if there was any data to be flushed. */ apr_bucket_delete(bucket); } } #if defined AP_BUCKET_IS_EOC else if (AP_BUCKET_IS_EOC(bucket)) { /* The special "EOC" bucket means a shutdown is needed; * - turn off buffering in nspr_filter_out_write * - issue the SSL_shutdown */ filter_ctx->nobuffer = 1; status = nss_filter_io_shutdown(filter_ctx, f->c, 0); if (status != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_INFO, status, f->c->base_server, "SSL filter error shutting down I/O"); } if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { return status; } break; } #endif else { /* filter output */ const char *data; apr_size_t len; status = apr_bucket_read(bucket, &data, &len, rblock); if (APR_STATUS_IS_EAGAIN(status)) { /* No data available: flush... */ if (nspr_filter_out_flush(filter_ctx->outctx) < 0) { status = outctx->rc; break; } rblock = APR_BLOCK_READ; continue; /* and try again with a blocking read. */ } rblock = APR_NONBLOCK_READ; if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) { break; } status = nss_filter_write(f, data, len); apr_bucket_delete(bucket); if (status != APR_SUCCESS) { break; } } } return status; } static void nss_io_output_create(nss_filter_ctx_t *filter_ctx, conn_rec *c) { nspr_filter_out_ctx_t *outctx = apr_palloc(c->pool, sizeof(*outctx)); outctx->filter_ctx = filter_ctx; outctx->bb = apr_brigade_create(c->pool, c->bucket_alloc); outctx->blen = 0; outctx->length = 0; filter_ctx->outctx = outctx; return; } /* 128K maximum buffer size by default. */ #ifndef SSL_MAX_IO_BUFFER #define SSL_MAX_IO_BUFFER (128 * 1024) #endif struct modnss_buffer_ctx { apr_bucket_brigade *bb; apr_pool_t *pool; }; int nss_io_buffer_fill(request_rec *r, apr_size_t maxlen) { conn_rec *c = r->connection; struct modnss_buffer_ctx *ctx; apr_bucket_brigade *tempb; apr_off_t total = 0; /* total length buffered */ int eos = 0; /* non-zero once EOS is seen */ /* Create the context which will be passed to the input filter. */ ctx = apr_palloc(r->pool, sizeof *ctx); apr_pool_create(&ctx->pool, r->pool); ctx->bb = apr_brigade_create(ctx->pool, c->bucket_alloc); /* ... and a temporary brigade. */ tempb = apr_brigade_create(r->pool, c->bucket_alloc); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "filling buffer, max size " "%" APR_SIZE_T_FMT " bytes", maxlen); do { apr_status_t rv; apr_bucket *e, *next; /* The request body is read from the protocol-level input * filters; the buffering filter will reinject it from that * level, allowing content/resource filters to run later, if * necessary. */ rv = ap_get_brigade(r->proto_input_filters, tempb, AP_MODE_READBYTES, APR_BLOCK_READ, 8192); if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "could not read request body for SSL buffer"); return HTTP_INTERNAL_SERVER_ERROR; } /* Iterate through the returned brigade: setaside each bucket * into the context's pool and move it into the brigade. */ for (e = APR_BRIGADE_FIRST(tempb); e != APR_BRIGADE_SENTINEL(tempb) && !eos; e = next) { const char *data; apr_size_t len; next = APR_BUCKET_NEXT(e); if (APR_BUCKET_IS_EOS(e)) { eos = 1; } else if (!APR_BUCKET_IS_METADATA(e)) { rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "could not read bucket for SSL buffer"); return HTTP_INTERNAL_SERVER_ERROR; } total += len; } rv = apr_bucket_setaside(e, ctx->pool); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "could not setaside bucket for SSL buffer"); return HTTP_INTERNAL_SERVER_ERROR; } APR_BUCKET_REMOVE(e); APR_BRIGADE_INSERT_TAIL(ctx->bb, e); } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "total of %" APR_OFF_T_FMT " bytes in buffer, eos=%d", total, eos); /* Fail if this exceeds the maximum buffer size. */ if (total > maxlen) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "request body exceeds maximum size (%" APR_SIZE_T_FMT ") for SSL buffer", maxlen); return HTTP_REQUEST_ENTITY_TOO_LARGE; } } while (!eos); apr_brigade_destroy(tempb); /* Insert the filter which will supply the buffered data. */ ap_add_input_filter(nss_io_buffer, ctx, r, c); return 0; } /* This input filter supplies the buffered request body to the caller * from the brigade stored in f->ctx. */ static apr_status_t nss_io_filter_buffer(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t bytes) { struct modnss_buffer_ctx *ctx = f->ctx; apr_status_t rv; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "read from buffered SSL brigade, mode %d, " "%" APR_OFF_T_FMT " bytes", mode, bytes); if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { return APR_ENOTIMPL; } if (mode == AP_MODE_READBYTES) { apr_bucket *e; /* Partition the buffered brigade. */ rv = apr_brigade_partition(ctx->bb, bytes, &e); if (rv && rv != APR_INCOMPLETE) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "could not partition buffered SSL brigade"); ap_remove_input_filter(f); return rv; } /* If the buffered brigade contains less then the requested * length, just pass it all back. */ if (rv == APR_INCOMPLETE) { APR_BRIGADE_CONCAT(bb, ctx->bb); } else { apr_bucket *d = APR_BRIGADE_FIRST(ctx->bb); e = APR_BUCKET_PREV(e); /* Unsplice the partitioned segment and move it into the * passed-in brigade; no convenient way to do this with * the APR_BRIGADE_* macros. */ APR_RING_UNSPLICE(d, e, link); APR_RING_SPLICE_HEAD(&bb->list, d, e, apr_bucket, link); APR_BRIGADE_CHECK_CONSISTENCY(bb); APR_BRIGADE_CHECK_CONSISTENCY(ctx->bb); } } else { /* Split a line into the passed-in brigade. */ rv = apr_brigade_split_line(bb, ctx->bb, mode, bytes); if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "could not split line from buffered SSL brigade"); ap_remove_input_filter(f); return rv; } } if (APR_BRIGADE_EMPTY(ctx->bb)) { apr_bucket *e = APR_BRIGADE_LAST(bb); /* Ensure that the brigade is terminated by an EOS if the * buffered request body has been entirely consumed. */ if (e == APR_BRIGADE_SENTINEL(bb) || !APR_BUCKET_IS_EOS(e)) { e = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "buffered SSL brigade now exhausted; removing filter"); ap_remove_input_filter(f); } return APR_SUCCESS; } static void nss_io_input_add_filter(nss_filter_ctx_t *filter_ctx, conn_rec *c, PRFileDesc *ssl) { nspr_filter_in_ctx_t *inctx; inctx = apr_palloc(c->pool, sizeof(*inctx)); filter_ctx->pInputFilter = ap_add_input_filter(nss_io_filter, inctx, NULL, c); inctx->f = filter_ctx->pInputFilter; inctx->rc = APR_SUCCESS; inctx->mode = AP_MODE_READBYTES; inctx->cbuf.length = 0; inctx->bb = apr_brigade_create(c->pool, c->bucket_alloc); inctx->block = APR_BLOCK_READ; inctx->pool = c->pool; inctx->filter_ctx = filter_ctx; filter_ctx->inctx = inctx; } void nss_io_filter_init(conn_rec *c, PRFileDesc *ssl) { nss_filter_ctx_t *filter_ctx; filter_ctx = apr_palloc(c->pool, sizeof(nss_filter_ctx_t)); filter_ctx->pOutputFilter = ap_add_output_filter(nss_io_filter, filter_ctx, NULL, c); nss_io_input_add_filter(filter_ctx, c, ssl); nss_io_output_create(filter_ctx, c); filter_ctx->pssl = ssl; filter_ctx->c = c; ssl->lower->secret = (PRFilePrivate *)filter_ctx; apr_pool_cleanup_register(c->pool, (void*)filter_ctx, nss_io_filter_cleanup, apr_pool_cleanup_null); return; } void nss_io_filter_register(apr_pool_t *p) { ap_register_input_filter (nss_io_filter, nss_io_filter_input, NULL, AP_FTYPE_CONNECTION + 5); ap_register_output_filter (nss_io_filter, nss_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5); ap_register_input_filter (nss_io_buffer, nss_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL - 1); return; } PRFileDesc * nss_io_new_fd() { PRFileDesc *ssl = PR_CreateIOLayerStub(gIdentity, &gMethods); return ssl; } static PRStatus PR_CALLBACK nspr_filter_getpeername(PRFileDesc *fd, PRNetAddr *addr) { nss_filter_ctx_t *filter_ctx; conn_rec *c; /* This can occur when doing SSL_ImportFD(NULL, something); */ if (fd->secret == NULL) return PR_FAILURE; filter_ctx = (nss_filter_ctx_t *)(fd->secret); c = filter_ctx->c; #if AP_SERVER_MINORVERSION_NUMBER <= 2 return PR_StringToNetAddr(c->remote_ip, addr); #else return PR_StringToNetAddr(c->client_ip, addr); #endif } /* * Translate NSPR PR_GetSocketOption() calls into apr_socket_opt_get() calls. */ static PRStatus PR_CALLBACK nspr_filter_getsocketoption(PRFileDesc *fd, PRSocketOptionData *data) { nss_filter_ctx_t *filter_ctx = (nss_filter_ctx_t *)(fd->secret); conn_rec *c = filter_ctx->c; SSLConnRec *sslconn = myConnConfig(c); /* for the Apache socket */ apr_int32_t on; PRStatus rv = PR_FAILURE; switch(data->option) { case PR_SockOpt_Nonblocking: if (apr_socket_opt_get(sslconn->client_socket, APR_SO_NONBLOCK, &on) == APR_SUCCESS) { data->value.non_blocking = (on == 1) ? PR_TRUE : PR_FALSE; rv = PR_SUCCESS; } break; case PR_SockOpt_Linger: if (apr_socket_opt_get(sslconn->client_socket, APR_SO_LINGER, &on) == APR_SUCCESS) { data->value.linger.polarity = (on == 1) ? PR_TRUE : PR_FALSE; data->value.linger.linger = APR_MAX_SECS_TO_LINGER; rv = PR_SUCCESS; } break; case PR_SockOpt_NoDelay: if (apr_socket_opt_get(sslconn->client_socket, APR_TCP_NODELAY, &on) == APR_SUCCESS) { data->value.no_delay = (on == 1) ? PR_TRUE : PR_FALSE; rv = PR_SUCCESS; } case PR_SockOpt_Reuseaddr: if (apr_socket_opt_get(sslconn->client_socket, APR_SO_REUSEADDR, &on) == APR_SUCCESS) { data->value.reuse_addr = (on == 1) ? PR_TRUE : PR_FALSE; rv = PR_SUCCESS; } break; case PR_SockOpt_Keepalive: /* has separate #define in Apache, use it */ if (apr_socket_opt_get(sslconn->client_socket, APR_SO_KEEPALIVE, &on) == APR_SUCCESS) { data->value.keep_alive = (on == 1) ? PR_TRUE : PR_FALSE; rv = PR_SUCCESS; } break; case PR_SockOpt_RecvBufferSize: case PR_SockOpt_SendBufferSize: ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "For sendbuffersize and recvbuffersize we can only see if they are on, not the value."); break; case PR_SockOpt_McastLoopback: case PR_SockOpt_MaxSegment: case PR_SockOpt_IpTimeToLive: case PR_SockOpt_IpTypeOfService: case PR_SockOpt_McastTimeToLive: case PR_SockOpt_McastInterface: ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "Unsupported or socket option."); break; default: ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "Unknown socket option."); break; } return rv; } /* * Translate NSPR PR_SetSocketOption() calls into apr_socket_opt_set() calls. */ static PRStatus PR_CALLBACK nspr_filter_setsocketOption(PRFileDesc *fd, const PRSocketOptionData *data) { nss_filter_ctx_t *filter_ctx = (nss_filter_ctx_t *)(fd->secret); conn_rec *c = filter_ctx->c; SSLConnRec *sslconn = myConnConfig(c); /* for the Apache socket */ PRStatus rv = PR_FAILURE; switch(data->option) { case PR_SockOpt_Nonblocking: if (apr_socket_opt_set(sslconn->client_socket, APR_SO_NONBLOCK, data->value.non_blocking) == APR_SUCCESS) { rv = PR_SUCCESS; } break; case PR_SockOpt_Linger: if (apr_socket_opt_set(sslconn->client_socket, APR_SO_LINGER, data->value.linger.polarity) == APR_SUCCESS) { rv = PR_SUCCESS; } break; case PR_SockOpt_NoDelay: if (apr_socket_opt_set(sslconn->client_socket, APR_TCP_NODELAY, data->value.no_delay) == APR_SUCCESS) { rv = PR_SUCCESS; } case PR_SockOpt_Reuseaddr: if (apr_socket_opt_set(sslconn->client_socket, APR_SO_REUSEADDR, data->value.reuse_addr) == APR_SUCCESS) { rv = PR_SUCCESS; } break; case PR_SockOpt_Keepalive: /* has separate #define in Apache, use it */ if (apr_socket_opt_set(sslconn->client_socket, APR_SO_KEEPALIVE, data->value.keep_alive) == APR_SUCCESS) { rv = PR_SUCCESS; } break; case PR_SockOpt_RecvBufferSize: if (apr_socket_opt_set(sslconn->client_socket, APR_SO_RCVBUF, data->value.recv_buffer_size) == APR_SUCCESS) { rv = PR_SUCCESS; } break; case PR_SockOpt_SendBufferSize: if (apr_socket_opt_set(sslconn->client_socket, APR_SO_SNDBUF, data->value.send_buffer_size) == APR_SUCCESS) { rv = PR_SUCCESS; } break; case PR_SockOpt_McastLoopback: case PR_SockOpt_MaxSegment: case PR_SockOpt_IpTimeToLive: case PR_SockOpt_IpTypeOfService: case PR_SockOpt_McastTimeToLive: case PR_SockOpt_McastInterface: ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "Unsupported or socket option."); break; default: ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, "Unknown socket option."); break; } return rv; } static PRStatus PR_CALLBACK nspr_filter_shutdown(PRFileDesc *fd, PRIntn how) { return PR_SUCCESS; } static PRStatus PR_CALLBACK nspr_filter_close(PRFileDesc *fd) { return PR_SUCCESS; } /* Wrapper that ignores flags and timeouts */ static PRInt32 PR_CALLBACK nspr_filter_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { return nspr_filter_in_read(fd, buf, amount); } /* Wrapper that ignores flags and timeouts */ static PRInt32 PR_CALLBACK nspr_filter_send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { return nspr_filter_out_write(fd, buf, amount); } /* * Called once to initialize the NSPR layer that we push for each * request. */ int nss_io_layer_init() { const PRIOMethods *defaultMethods; int rc = 1; if (gIdentity != PR_INVALID_IO_LAYER) { /* already initialized */ return PR_FAILURE; } gIdentity = PR_GetUniqueIdentity("ApacheNSSLayer"); if (gIdentity == PR_INVALID_IO_LAYER) return PR_FAILURE; defaultMethods = PR_GetDefaultIOMethods(); if (defaultMethods == NULL) return PR_FAILURE; gMethods = *defaultMethods; gMethods.close = nspr_filter_close; gMethods.read = nspr_filter_in_read; gMethods.write = nspr_filter_out_write; gMethods.recv = nspr_filter_recv; gMethods.send = nspr_filter_send;; gMethods.getpeername = nspr_filter_getpeername; gMethods.shutdown = nspr_filter_shutdown; gMethods.getsocketoption = nspr_filter_getsocketoption; gMethods.setsocketoption = nspr_filter_setsocketOption; return rc; } SECStatus nss_AuthCertificate(void *arg, PRFileDesc *socket, PRBool checksig, PRBool isServer) { SECStatus status; if (!arg || !socket) { return SECFailure; } status = SSL_AuthCertificate(arg, socket, checksig, isServer); /* The certificate is copied to sslconn->client_cert in * nss_hook_ReadReq() */ return status; } mod_nss-1.0.12/nss_engine_kernel.c000066400000000000000000001053711260357105600171050ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" #include "nss_engine_cipher.h" #include "secerr.h" static void HandshakeDone(PRFileDesc *fd, void *doneflag); extern cipher_properties ciphers_def[]; extern int ciphernum; /* * Post Read Request Handler */ int nss_hook_ReadReq(request_rec *r) { SSLConnRec *sslconn = myConnConfig(r->connection); PRFileDesc *ssl = sslconn ? sslconn->ssl : NULL; SECItem *hostInfo = NULL; SSLSrvConfigRec *sc = mySrvConfig(r->server); if (!sslconn) { return DECLINED; } if (sslconn->non_nss_request) { const char *errmsg; char *thisurl; char *thisport = ""; int port = ap_get_server_port(r); if (!ap_is_default_port(port, r)) { thisport = apr_psprintf(r->pool, ":%u", port); } thisurl = ap_escape_html(r->pool, apr_psprintf(r->pool, "https://%s%s/", ap_get_server_name(r), thisport)); errmsg = apr_psprintf(r->pool, "Reason: You're speaking plain HTTP " "to an SSL-enabled server port.
\n" "Instead use the HTTPS scheme to access " "this URL, please.
\n" "
Hint: " "%s
", thisurl, thisurl); apr_table_setn(r->notes, "error-notes", errmsg); /* Now that we have caught this error, forget it. we are done * with using SSL on this request. */ sslconn->non_nss_request = 0; return HTTP_BAD_REQUEST; } /* Get the SSL connection structure and perform the * delayed interlinking from SSL back to request_rec */ if (!ssl) { return DECLINED; } /* * SNI is on by default. You can switch SNI off by setting * NSSSNI off. */ if (sc->sni) { hostInfo = SSL_GetNegotiatedHostInfo(ssl); if (hostInfo != NULL) { if (ap_is_initial_req(r) && (hostInfo->len != 0)) { char *servername = NULL; char *host, *scope_id; apr_port_t port; apr_status_t rv; apr_pool_t *s_p; apr_pool_create(&s_p, NULL); servername = apr_pstrndup(s_p, (char *) hostInfo->data, hostInfo->len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "SNI request for %s", servername); if (!r->hostname) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Hostname %s provided via SNI, but no hostname" " provided in HTTP request", servername); apr_pool_destroy(s_p); SECITEM_FreeItem(hostInfo, PR_TRUE); return HTTP_BAD_REQUEST; } rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool); if (rv != APR_SUCCESS || scope_id) { apr_pool_destroy(s_p); SECITEM_FreeItem(hostInfo, PR_TRUE); return HTTP_BAD_REQUEST; } if (strcasecmp(host, servername)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Hostname %s provided via SNI and hostname %s provided" " via HTTP are different", servername, host); apr_pool_destroy(s_p); SECITEM_FreeItem(hostInfo, PR_TRUE); return HTTP_BAD_REQUEST; } apr_pool_destroy(s_p); SECITEM_FreeItem(hostInfo, PR_TRUE); } } else if (((sc->strict_sni_vhost_check) || (mySrvConfig(r->server))->strict_sni_vhost_check) && r->connection->vhost_lookup_data) { /* * We are using a name based configuration here, but no hostname * was provided via SNI. Don't allow that if are requested to do * strict checking. Check whether this strict checking was set * up either in the server config we used for handshaking or in * our current server. This should avoid insecure configuration * by accident. */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "No hostname was provided via SNI for a name based" " virtual host"); apr_table_setn(r->notes, "error-notes", "Reason: The client software did not provide a " "hostname using Server Name Indication (SNI), " "which is required to access this server.
\n"); return HTTP_FORBIDDEN; } } /* * Log information about incoming HTTPS requests */ #if AP_SERVER_MINORVERSION_NUMBER <= 2 if (r->server->loglevel >= APLOG_INFO && ap_is_initial_req(r)) { #else if (r->server->log.level >= APLOG_INFO && ap_is_initial_req(r)) { #endif ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "%s HTTPS request received for child %ld (server %s)", (r->connection->keepalives <= 0 ? "Initial (No.1)" : apr_psprintf(r->pool, "Subsequent (No.%d)", r->connection->keepalives+1)), r->connection->id, nss_util_vhostid(r->pool, r->server)); } if (sslconn->client_cert != NULL) CERT_DestroyCertificate(sslconn->client_cert); sslconn->client_cert = SSL_PeerCertificate(ssl); sslconn->client_dn = NULL; return DECLINED; } /* * Access Handler */ int nss_hook_Access(request_rec *r) { SSLDirConfigRec *dc = myDirConfig(r); SSLSrvConfigRec *sc = mySrvConfig(r->server); SSLConnRec *sslconn = myConnConfig(r->connection); PRFileDesc *ssl = sslconn ? sslconn->ssl : NULL; apr_array_header_t *requires; nss_require_t *nss_requires; char *cp; int ok, i; BOOL renegotiate = FALSE, renegotiate_quick = FALSE; CERTCertificate *cert; CERTCertificate *peercert; int verify_old, verify; PRBool ciphers_old[ciphernum]; PRBool ciphers_new[ciphernum]; char * cipher = NULL; char * ciphers = NULL; PRBool cipher_in_list = PR_FALSE; /* * Support for SSLRequireSSL directive */ if (dc->bSSLRequired && !ssl) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "access to %s failed, reason: %s", r->filename, "SSL connection required"); /* remember forbidden access for strict require option */ apr_table_setn(r->notes, "ssl-access-forbidden", "1"); return HTTP_FORBIDDEN; } /* * Check to see if SSL protocol is enabled. If it's not then * no further access control checks are relevant. The test for * sc->enabled is probably strictly unnecessary */ if (!((sc->enabled == TRUE) || !ssl)) { return DECLINED; } /* * Support for per-directory reconfigured SSL connection parameters. * * This is implemented by forcing an SSL renegotiation with the * reconfigured parameter suite. But Apache's internal API processing * makes our life very hard here, because when internal sub-requests occur * we nevertheless should avoid multiple unnecessary SSL handshakes (they * require extra network I/O and especially time to perform). * * But the optimization for filtering out the unnecessary handshakes isn't * obvious and trivial. Especially because while Apache is in its * sub-request processing the client could force additional handshakes, * too. And these take place perhaps without our notice. So the only * possibility is to explicitly _ask_ OpenSSL whether the renegotiation * has to be performed or not. It has to performed when some parameters * which were previously known (by us) are not those we've now * reconfigured (as known by OpenSSL) or (in optimized way) at least when * the reconfigured parameter suite is stronger (more restrictions) than * the currently active one. */ /* * Override of NSSCipherSuite * * We provide two options here: * * o The paranoid and default approach where we force a renegotiation when * the cipher suite changed in _any_ way (which is straight-forward but * often forces renegotiations too often and is perhaps not what the * user actually wanted). * * o The optimized and still secure way where we force a renegotiation * only if the currently active cipher is no longer contained in the * reconfigured/new cipher suite. Any other changes are not important * because it's the servers choice to select a cipher from the ones the * client supports. So as long as the current cipher is still in the new * cipher suite we're happy. Because we can assume we would have * selected it again even when other (better) ciphers exists now in the * new cipher suite. This approach is fine because the user explicitly * has to enable this via ``NSSOptions +OptRenegotiate''. So we do no * implicit optimizations. */ if (dc->szCipherSuite) { /* remember old state */ for (i=0; i < ciphernum; i++) { SSL_CipherPrefGet(ssl, ciphers_def[i].num, &ciphers_old[i]); } if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) { int on, keySize, secretKeySize; char *issuer, *subject; SSL_SecurityStatus(ssl, &on, &cipher, &keySize, &secretKeySize, &issuer, &subject); } /* configure new state */ for (i=0; iszCipherSuite); if (nss_parse_ciphers(r->server, ciphers, ciphers_new) < 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "Unable to reconfigure (per-directory) " "permitted SSL ciphers"); nss_log_nss_error(APLOG_MARK, APLOG_ERR, r->server); free(ciphers); return HTTP_FORBIDDEN; } free(ciphers); /* Disable all ciphers so only the ones we want will be available */ for (i = 0; i < SSL_NumImplementedCiphers; i++) { SSL_CipherPrefSet(ssl, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED); } /* Actually enable the selected ciphers. Also check to see if the existing cipher is in the new list for a possible optimization later. */ for (i=0; inOptions & SSL_OPT_OPTRENEGOTIATE) { if (cipher_in_list != PR_TRUE) renegotiate = TRUE; } else { /* paranoid way */ for (i=0; iserver, "Reconfigured cipher suite will force renegotiation"); } } /* * override of SSLVerifyClient * * We force a renegotiation if the reconfigured/new verify type is * stronger than the currently active verify type. * * The order is: none << optional_no_ca << optional << require * * Additionally the following optimization is possible here: When the * currently active verify type is "none" but a client certificate is * already known/present, it's enough to manually force a client * verification but at least skip the I/O-intensive renegotation * handshake. */ if (dc->nVerifyClient != SSL_CVERIFY_UNSET) { PRInt32 on; /* remember old state */ SSL_OptionGet(ssl, SSL_REQUIRE_CERTIFICATE, &on); if (on == PR_TRUE) { verify_old = SSL_CVERIFY_REQUIRE; } else { SSL_OptionGet(ssl, SSL_REQUEST_CERTIFICATE, &on); if (on == PR_TRUE) verify_old = SSL_CVERIFY_OPTIONAL; else verify_old = SSL_CVERIFY_NONE; } /* configure new state */ verify = dc->nVerifyClient; if (verify == SSL_CVERIFY_REQUIRE) { SSL_OptionSet(ssl, SSL_REQUEST_CERTIFICATE, PR_TRUE); SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS); } else if (verify == SSL_CVERIFY_OPTIONAL) { SSL_OptionSet(ssl, SSL_REQUEST_CERTIFICATE, PR_TRUE); SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER); } else { SSL_OptionSet(ssl, SSL_REQUEST_CERTIFICATE, PR_FALSE); SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER); } /* determine whether we've to force a renegotiation */ if (!renegotiate && verify != verify_old) { if (((verify_old == SSL_CVERIFY_NONE) && (verify != SSL_CVERIFY_NONE)) || (!(verify_old & SSL_CVERIFY_OPTIONAL) && (verify & SSL_CVERIFY_OPTIONAL)) || (!(verify_old & SSL_CVERIFY_REQUIRE) && (verify & SSL_CVERIFY_REQUIRE))) { renegotiate = TRUE; /* optimization */ if ((dc->nOptions & SSL_OPT_OPTRENEGOTIATE) && (verify_old == SSL_CVERIFY_NONE) && ((peercert = SSL_PeerCertificate(ssl)) != NULL)) { renegotiate_quick = TRUE; CERT_DestroyCertificate(peercert); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Changed client verification type will force " "%srenegotiation", renegotiate_quick ? "quick " : ""); } } } /* If a renegotiation is now required for this location, and the * request includes a message body (and the client has not * requested a "100 Continue" response), then the client will be * streaming the request body over the wire already. In that * case, it is not possible to stop and perform a new SSL * handshake immediately; once the SSL library moves to the * "accept" state, it will reject the SSL packets which the client * is sending for the request body. * * To allow authentication to complete in this auth hook, the * solution used here is to fill a (bounded) buffer with the * request body, and then to reinject that request body later. */ if (renegotiate && !renegotiate_quick && (apr_table_get(r->headers_in, "transfer-encoding") || (apr_table_get(r->headers_in, "content-length") && strcmp(apr_table_get(r->headers_in, "content-length"), "0"))) && !r->expecting_100) { int rv; apr_size_t rsize; rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE : dc->nRenegBufferSize; if (rsize > 0) { /* Fill the I/O buffer with the request body if possible. */ rv = nss_io_buffer_fill(r, rsize); } else { /* If the reneg buffer size is set to zero, just fail. */ rv = HTTP_REQUEST_ENTITY_TOO_LARGE; } if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "could not buffer message body to allow " "SSL renegotiation to proceed"); return rv; } } /* * now do the renegotiation if anything was actually reconfigured */ if (renegotiate) { /* * Now we force the SSL renegotation by sending the Hello Request * message to the client. Here we have to do a workaround: Actually * OpenSSL returns immediately after sending the Hello Request (the * intent AFAIK is because the SSL/TLS protocol says it's not a must * that the client replies to a Hello Request). But because we insist * on a reply (anything else is an error for us) we have to go to the * ACCEPT state manually. Using SSL_set_accept_state() doesn't work * here because it resets too much of the connection. So we set the * state explicitly and continue the handshake manually. */ ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Requesting connection re-negotiation"); if (renegotiate_quick) { SECStatus rv; CERTCertificate *peerCert; void *pinArg; /* perform just a manual re-verification of the peer */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Performing quick renegotiation: " "just re-verifying the peer"); peerCert = SSL_PeerCertificate(sslconn->ssl); pinArg = SSL_RevealPinArg(sslconn->ssl); rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, PR_TRUE, certUsageSSLClient, pinArg); CERT_DestroyCertificate(peerCert); if (rv != SECSuccess) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Re-negotiation handshake failed: " "Client verification failed"); return HTTP_FORBIDDEN; } /* The cert is ok, fall through to the check SSLRequires */ } else { int handshake_done = 0; int result = 0; /* do a full renegotiation */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Performing full renegotiation: " "complete handshake protocol"); /* Do NOT call SSL_ResetHandshake as this will tear down the * existing connection. */ if (SSL_HandshakeCallback(ssl, HandshakeDone, (void *)&handshake_done) || SSL_ReHandshake(ssl, PR_TRUE)) { int errCode = PR_GetError(); if (errCode == SEC_ERROR_INVALID_ARGS) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Re-negotation request failed: " "trying to do client authentication on a non-SSL3 connection"); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Re-negotation request failed: " "returned error %d", errCode); } r->connection->aborted = 1; return HTTP_FORBIDDEN; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Awaiting re-negotiation handshake"); while (!handshake_done) { apr_bucket_brigade *bb; conn_rec *c = r->connection; bb = apr_brigade_create(c->pool, c->bucket_alloc); result = SSL_ForceHandshake(ssl); if (result >= 0) { /* This flag gets set by the NSS callback */ if (handshake_done) break; /* We need to force a read so the SSL data can be * handled */ if ((result = ap_get_brigade(c->input_filters, bb, AP_MODE_GETLINE, APR_BLOCK_READ, HUGE_STRING_LEN) != APR_SUCCESS || APR_BRIGADE_EMPTY(bb))) { apr_brigade_destroy(bb); break; } } else { ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Read error %d", PR_GetError()); break; } } /* Reset the ssl callback */ SSL_HandshakeCallback(ssl, NULL, NULL); if (result < 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Re-negotiation handshake failed: " "Not accepted by client!?"); #if 0 r->connection->aborted = 1; #endif return HTTP_FORBIDDEN; } } if (cipher || !cipher_in_list) { int on, keySize, secretKeySize; char *issuer, *subject; SSL_SecurityStatus(ssl, &on, &cipher, &keySize, &secretKeySize, &issuer, &subject); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Re-negotiated cipher %s", cipher); } /* * Remember the peer certificate's DN */ if ((cert = SSL_PeerCertificate(ssl))) { if (sslconn->client_cert) { CERT_DestroyCertificate(sslconn->client_cert); } sslconn->client_cert = cert; sslconn->client_dn = NULL; } } /* If we're trying to have the user name set from a client * certificate then we need to set it here. This should be safe as * the user name probably isn't important from an auth checking point * of view as the certificate supplied acts in that capacity. * However, if FakeAuth is being used then this isn't the case so * we need to postpone setting the username until later. */ if ((dc->nOptions & SSL_OPT_FAKEBASICAUTH) == 0 && dc->szUserName) { char *val = nss_var_lookup(r->pool, r->server, r->connection, r, (char *)dc->szUserName); if (val && val[0]) r->user = val; } /* * Check SSLRequire boolean expressions */ requires = dc->aRequirement; nss_requires = (nss_require_t *)requires->elts; for (i = 0; i < requires->nelts; i++) { nss_require_t *req = &nss_requires[i]; ok = nss_expr_exec(r, req->mpExpr); if (ok < 0) { cp = apr_psprintf(r->pool, "Failed to execute " "SSL requirement expression: %s", nss_expr_get_error()); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "access to %s failed, reason: %s", r->filename, cp); /* remember forbidden access for strict require option */ apr_table_setn(r->notes, "ssl-access-forbidden", "1"); return HTTP_FORBIDDEN; } if (ok != 1) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Access to %s denied for %s " "(requirement expression not fulfilled)", #if AP_SERVER_MINORVERSION_NUMBER <= 2 r->filename, r->connection->remote_ip); #else r->filename, r->connection->client_ip); #endif ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Failed expression: %s", req->cpExpr); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "access to %s failed, reason: %s", r->filename, "SSL requirement expression not fulfilled " "(see SSL logfile for more details)"); /* remember forbidden access for strict require option */ apr_table_setn(r->notes, "ssl-access-forbidden", "1"); return HTTP_FORBIDDEN; } } /* * Else access is granted from our point of view (except vendor * handlers override). But we have to return DECLINED here instead * of OK, because mod_auth and other modules still might want to * deny access. */ return DECLINED; } /* * Authentication Handler: * Fake a Basic authentication from the X509 client certificate. * * This must be run fairly early on to prevent a real authentication from * occuring, in particular it must be run before anything else that * authenticates a user. This means that the Module statement for this * module should be LAST in the Configuration file. */ int nss_hook_UserCheck(request_rec *r) { SSLConnRec *sslconn = myConnConfig(r->connection); SSLSrvConfigRec *sc = mySrvConfig(r->server); SSLDirConfigRec *dc = myDirConfig(r); char *clientdn; const char *auth_line, *username, *password; /* * Additionally forbid access (again) * when strict require option is used. */ if ((dc->nOptions & SSL_OPT_STRICTREQUIRE) && (apr_table_get(r->notes, "ssl-access-forbidden"))) { return HTTP_FORBIDDEN; } /* * We decline when we are in a subrequest. The Authorization header * would already be present if it was added in the main request. */ if (!ap_is_initial_req(r)) { return DECLINED; } /* * Make sure the user is not able to fake the client certificate * based authentication by just entering an X.509 Subject DN * ("/XX=YYY/XX=YYY/..") as the username and "password" as the * password. */ if ((auth_line = apr_table_get(r->headers_in, "Authorization"))) { if (strcEQ(ap_getword(r->pool, &auth_line, ' '), "Basic")) { while ((*auth_line == ' ') || (*auth_line == '\t')) { auth_line++; } auth_line = ap_pbase64decode(r->pool, auth_line); username = ap_getword_nulls(r->pool, &auth_line, ':'); password = auth_line; if ((username[0] == '/') && strEQ(password, "password")) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Encountered FakeBasicAuth spoof: %s", username); return HTTP_FORBIDDEN; } } } /* * We decline operation in various situations... * - NSSOptions +FakeBasicAuth not configured * - r->user already authenticated * - ssl not enabled * - client did not present a certificate */ if (!((sc->enabled == TRUE) && sslconn && sslconn->ssl && sslconn->client_cert) || !(dc->nOptions & SSL_OPT_FAKEBASICAUTH) || r->user) { return DECLINED; } if (!sslconn->client_dn) { char * cp = CERT_NameToAscii(&sslconn->client_cert->subject); sslconn->client_dn = apr_pstrcat(r->connection->pool, "/", cp, NULL); PORT_Free(cp); } clientdn = (char *)sslconn->client_dn; /* * Fake a password - which one would be immaterial, as, it seems, an empty * password in the users file would match ALL incoming passwords, if only * we were using the standard crypt library routine. Unfortunately, OpenSSL * "fixes" a "bug" in crypt and thus prevents blank passwords from * working. (IMHO what they really fix is a bug in the users of the code * - failing to program correctly for shadow passwords). We need, * therefore, to provide a password. This password can be matched by * adding the string "xxj31ZMTZzkVA" as the password in the user file. * This is just the crypted variant of the word "password" ;-) * * The NSS module is retaining this for compatibility purposes. */ auth_line = apr_pstrcat(r->pool, "Basic ", ap_pbase64encode(r->pool, apr_pstrcat(r->pool, clientdn, ":password", NULL)), NULL); apr_table_set(r->headers_in, "Authorization", auth_line); ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Faking HTTP Basic Auth header: \"Authorization: %s\"", auth_line); return DECLINED; } /* authorization phase */ int nss_hook_Auth(request_rec *r) { SSLDirConfigRec *dc = myDirConfig(r); ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "nss_hook_Auth"); /* * Additionally forbid access (again) * when strict require option is used. */ if ((dc->nOptions & SSL_OPT_STRICTREQUIRE) && (apr_table_get(r->notes, "ssl-access-forbidden"))) { return HTTP_FORBIDDEN; } return DECLINED; } /* * Fixup Handler */ static const char *nss_hook_Fixup_vars[] = { "SSL_VERSION_INTERFACE", "SSL_VERSION_LIBRARY", "SSL_PROTOCOL", "SSL_SECURE_RENEG", "SSL_CIPHER", "SSL_CIPHER_NAME", "SSL_CIPHER_EXPORT", "SSL_CIPHER_USEKEYSIZE", "SSL_CIPHER_ALGKEYSIZE", "SSL_CLIENT_VERIFY", "SSL_CLIENT_M_VERSION", "SSL_CLIENT_M_SERIAL", "SSL_CLIENT_V_START", "SSL_CLIENT_V_END", "SSL_CLIENT_V_REMAIN", "SSL_CLIENT_S_DN", "SSL_CLIENT_S_DN_C", "SSL_CLIENT_S_DN_ST", "SSL_CLIENT_S_DN_L", "SSL_CLIENT_S_DN_O", "SSL_CLIENT_S_DN_OU", "SSL_CLIENT_S_DN_CN", "SSL_CLIENT_S_DN_T", "SSL_CLIENT_S_DN_I", "SSL_CLIENT_S_DN_G", "SSL_CLIENT_S_DN_S", "SSL_CLIENT_S_DN_D", "SSL_CLIENT_S_DN_UID", "SSL_CLIENT_S_DN_Email", "SSL_CLIENT_I_DN", "SSL_CLIENT_I_DN_C", "SSL_CLIENT_I_DN_ST", "SSL_CLIENT_I_DN_L", "SSL_CLIENT_I_DN_O", "SSL_CLIENT_I_DN_OU", "SSL_CLIENT_I_DN_CN", "SSL_CLIENT_I_DN_T", "SSL_CLIENT_I_DN_I", "SSL_CLIENT_I_DN_G", "SSL_CLIENT_I_DN_S", "SSL_CLIENT_I_DN_D", "SSL_CLIENT_I_DN_UID", "SSL_CLIENT_I_DN_Email", "SSL_CLIENT_A_KEY", "SSL_CLIENT_A_SIG", "SSL_SERVER_M_VERSION", "SSL_SERVER_M_SERIAL", "SSL_SERVER_V_START", "SSL_SERVER_V_END", "SSL_SERVER_S_DN", "SSL_SERVER_S_DN_C", "SSL_SERVER_S_DN_ST", "SSL_SERVER_S_DN_L", "SSL_SERVER_S_DN_O", "SSL_SERVER_S_DN_OU", "SSL_SERVER_S_DN_CN", "SSL_SERVER_S_DN_T", "SSL_SERVER_S_DN_I", "SSL_SERVER_S_DN_G", "SSL_SERVER_S_DN_S", "SSL_SERVER_S_DN_D", "SSL_SERVER_S_DN_UID", "SSL_SERVER_S_DN_Email", "SSL_SERVER_I_DN", "SSL_SERVER_I_DN_C", "SSL_SERVER_I_DN_ST", "SSL_SERVER_I_DN_L", "SSL_SERVER_I_DN_O", "SSL_SERVER_I_DN_OU", "SSL_SERVER_I_DN_CN", "SSL_SERVER_I_DN_T", "SSL_SERVER_I_DN_I", "SSL_SERVER_I_DN_G", "SSL_SERVER_I_DN_S", "SSL_SERVER_I_DN_D", "SSL_SERVER_I_DN_UID", "SSL_SERVER_I_DN_Email", "SSL_SERVER_A_KEY", "SSL_SERVER_A_SIG", "SSL_SESSION_ID", NULL }; int nss_hook_Fixup(request_rec *r) { SSLConnRec *sslconn = myConnConfig(r->connection); SSLSrvConfigRec *sc = mySrvConfig(r->server); SSLDirConfigRec *dc = myDirConfig(r); PRFileDesc * ssl; apr_table_t *env = r->subprocess_env; char *var, *val = ""; int i; CERTCertificate *cert; CERTCertificateList *chain = NULL; SECItem *hostInfo = NULL; const char *servername; /* * Check to see if SSL is on */ if (!((sc->enabled == TRUE) && sslconn && (ssl = sslconn->ssl))) { return DECLINED; } /* * Set r->user if requested */ if (dc->szUserName) { val = nss_var_lookup(r->pool, r->server, r->connection, r, (char *)dc->szUserName); if (val && val[0]) { r->user = val; } } /* * Annotate the SSI/CGI environment with standard SSL information */ /* the always present HTTPS (=HTTP over SSL) flag! */ apr_table_setn(env, "HTTPS", "on"); /* add content of SNI TLS extension (if supplied with ClientHello) */ hostInfo = SSL_GetNegotiatedHostInfo(ssl); if (hostInfo) { servername = apr_pstrndup(r->pool, (char *) hostInfo->data, hostInfo->len); apr_table_set(env, "SSL_TLS_SNI", servername); SECITEM_FreeItem(hostInfo, PR_TRUE); } /* standard SSL environment variables */ if (dc->nOptions & SSL_OPT_STDENVVARS) { for (i = 0; nss_hook_Fixup_vars[i]; i++) { var = (char *)nss_hook_Fixup_vars[i]; val = nss_var_lookup(r->pool, r->server, r->connection, r, var); if (!strIsEmpty(val)) { apr_table_setn(env, var, val); } } } /* * On-demand bloat up the SSI/CGI environment with certificate data */ if (dc->nOptions & SSL_OPT_EXPORTCERTDATA) { val = nss_var_lookup(r->pool, r->server, r->connection, r, "SSL_SERVER_CERT"); apr_table_setn(env, "SSL_SERVER_CERT", val); val = nss_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_CERT"); apr_table_setn(env, "SSL_CLIENT_CERT", val); /* Need to fetch the entire SSL cert chain and add it to the * variable SSL_CLIENT_CERT_CHAIN_[0..n] */ cert = SSL_PeerCertificate(ssl); if (cert) chain = CERT_CertChainFromCert(cert, certUsageSSLClient, PR_TRUE); if (cert && chain) { int n; n = chain->len; CERT_DestroyCertificateList(chain); for (i = 0; i < n; i++) { var = apr_psprintf(r->pool, "SSL_CLIENT_CERT_CHAIN_%d", i); val = nss_var_lookup(r->pool, r->server, r->connection, r, var); if (val) { apr_table_setn(env, var, val); } } } if (cert) CERT_DestroyCertificate(cert); } return DECLINED; } static void HandshakeDone(PRFileDesc *fd, void *doneflag) { /* * This routine is called by SSL when the handshake is * complete. It sets local state so that the loop doing * reads from the socket can exit. */ *((int *)doneflag) = 1; } mod_nss-1.0.12/nss_engine_log.c000066400000000000000000000467571260357105600164220ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* _________________________________________________________________ ** ** Logfile Support ** _________________________________________________________________ */ #include "mod_nss.h" #include "prerror.h" #define NSPR_ERROR_BASE PR_NSPR_ERROR_BASE #define NSPR_MAX_ERROR (PR_MAX_ERROR - 1) #define LIBSEC_ERROR_BASE (-8192) #define LIBSEC_MAX_ERROR (LIBSEC_ERROR_BASE + 155) #define LIBSSL_ERROR_BASE (-12288) #define LIBSSL_MAX_ERROR (LIBSSL_ERROR_BASE + 114) typedef struct l_error_t { int errorNumber; const char *errorString; } l_error_t; l_error_t libsec_errors[] = { { 0, "I/O Error" }, { 1, "Library Failure" }, { 2, "Bad data was received" }, { 3, "Security library: output length error" }, { 4, "Security library has experienced an input length error" }, { 5, "Security library: invalid arguments" }, { 6, "Certificate contains invalid encryption or signature algorithm" }, { 7, "Security library: invalid AVA" }, { 8, "Certificate contains an invalid time value" }, { 9, "Certificate is improperly DER encoded" }, { 10, "Certificate has invalid signature" }, { 11, "Certificate has expired" }, { 12, "Certificate has been revoked" }, { 13, "Certificate is signed by an unknown issuer" }, { 14, "Invalid public key in certificate" }, { 15, "The security password entered is incorrect" }, { 16, "SEC_ERROR_UNUSED" }, { 17, "Security library: no nodelock" }, { 18, "Problem using certificate or key database" }, { 19, "Out of Memory" }, { 20, "Certificate is signed by an untrusted issuer" }, { 21, "Peer's certificate has been marked as not trusted" }, { 22, "Certificate already exists in your database" }, { 23, "Downloaded certificate's name duplicates one already in your database" }, { 24, "Error adding certificate to database" }, { 25, "Error refiling the key for this certificate" }, { 26, "The private key for this certificate cannot be found in key database" }, { 27, "This certificate is valid" }, { 28, "This certificate is not valid" }, { 29, "Cert Library: No Response" }, { 30, "The certificate issuer's certificate has expired. Check your system date and time" }, { 31, "The CRL for the certificate's issuer has expired. Update it or check your system date and time" }, { 32, "The CRL for the certificate's issuer has an invalid signature" }, { 33, "New CRL has an invalid format" }, { 34, "Certificate extension value is invalid" }, { 35, "Certificate extension not found" }, { 36, "Issuer certificate is invalid" }, { 37, "Certificate path length constraint is invalid" }, { 38, "Certificate usages field is invalid" }, { 39, "**Internal ONLY module**" }, { 40, "The key does not support the requested operation" }, { 41, "Certificate contains unknown critical extension" }, { 42, "New CRL is not later than the current one" }, { 43, "Not encrypted or signed: you do not yet have an email certificate" }, { 44, "Not encrypted: you do not have certificates for each of the recipients" }, { 45, "Cannot decrypt: you are not a recipient, or matching certificate and private key not found" }, { 46, "Cannot decrypt: key encryption algorithm does not match your certificate" }, { 47, "Signature verification failed: no signer found, too many signers found, or improper or corrupted data" }, { 48, "Unsupported or unknown key algorithm" }, { 49, "Cannot decrypt: encrypted using a disallowed algorithm or key size" }, { 50, "XP_Fortezza card has not been properly initialized. Please remove it and return it to your issuer" }, { 51, "XP_No Fortezza cards Found" }, { 52, "XP_No Fortezza card selected" }, { 53, "XP_Please select a personality to get more info on" }, { 54, "XP_Personality not found" }, { 55, "XP_No more information on that Personality" }, { 56, "XP_Invalid Pin" }, { 57, "XP_Couldn't initialize Fortezza personalities" }, { 58, "No KRL for this site's certificate has been found" }, { 59, "The KRL for this site's certificate has expired" }, { 60, "The KRL for this site's certificate has an invalid signature" }, { 61, "The key for this site's certificate has been revoked" }, { 62, "New KRL has an invalid format" }, { 63, "security library: need random data" }, { 64, "security library: no security module can perform the requested operation" }, { 65, "The security card or token does not exist, needs to be initialized, or has been removed" }, { 66, "security library: read-only database" }, { 67, "No slot or token was selected" }, { 68, "A certificate with the same nickname already exists" }, { 69, "A key with the same nickname already exists" }, { 70, "error while creating safe object" }, { 71, "error while creating baggage object" }, { 72, "Couldn't remove the principal" }, { 73, "Couldn't delete the privilege" }, { 74, "This principal doesn't have a certificate" }, { 75, "Required algorithm is not allowed" }, { 76, "Error attempting to export certificates" }, { 77, "Error attempting to import certificates" }, { 78, "Unable to import. Decoding error. File not valid" }, { 79, "Unable to import. Invalid MAC. Incorrect password or corrupt file" }, { 80, "Unable to import. MAC algorithm not supported" }, { 81, "SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE" }, { 82, "Unable to import. File structure is corrupt." }, { 83, "Unable to import. Encryption algorithm not supported." }, { 84, "Unable to import. File version not supported." }, { 85, "SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT" }, { 86, "Unable to import. Same nickname already exists in database." }, { 87, "The user pressed cancel." }, { 88, "Not imported, already in database." }, { 89, "Message not sent." }, { 90, "Certificate key usage inadequate for attempted operation." }, { 91, "Certificate type not approved for application." }, { 92, "Address in signing certificate does not match address in message headers." }, { 93, "Unable to import. Error attempting to import private key." }, { 94, "Unable to import. Error attempting to import certificate chain." }, { 95, "Unable to export. Unable to locate certificate or key by nickname." }, { 96, "Unable to export. Private Key could not be located and exported." }, { 97, "Unable to export. Unable to write the export file." }, { 98, "Unable to import. Unable to read the import file." }, { 99, "Unable to export. Key database corrupt or deleted." }, { 100, "Unable to generate public/private key pair." }, { 101, "Password entered is invalid. Please pick a different one." }, { 102, "Old password entered incorrectly. Please try again." }, { 103, "Certificate nickname already in use." }, { 104, "Peer FORTEZZA chain has a non-FORTEZZA Certificate." }, { 105, "A sensitive key cannot be moved to the slot where it is needed." }, { 106, "Invalid module name." }, { 107, "Invalid module path/filename" }, { 108, "Unable to add module" }, { 109, "Unable to delete module" }, { 110, "New KRL is not later than the current one." }, { 111, "New CKL has different issuer than current CKL. Delete current CKL" }, { 112, "The Certifying Authority for this certificate is not permitted to issue a certificate with this name" }, { 113, "The key revocation list for this certificate is not yet valid" }, { 114, "The certificate revocation list for this certificate is not yet valid" }, { 115, "The requested certificate could not be found" }, { 116, "The signer's certificate could not be found" }, { 117, "The location for the certificate status server has invalid format" }, { 118, "The OCSP response cannot be fully decoded; it is of an unknown type" }, { 119, "The OCSP server returned unexpected/invalid HTTP data" }, { 120, "The OCSP server found the request to be corrupted or improperly formed" }, { 121, "The OCSP server experienced an internal error" }, { 122, "The OCSP server suggests trying again later" }, { 123, "The OCSP server requires a signature on this request" }, { 124, "The OCSP server has refused this request as unauthorized" }, { 125, "The OCSP server returned an unrecognizable status" }, { 126, "The OCSP server has no status for the certificate" }, { 127, "You must enable OCSP before performing this operation" }, { 128, "You must set the OCSP default responder before performing this operation" }, { 129, "The response from the OCSP server was corrupted or improperly formed" }, { 130, "The signer of the OCSP response is not authorized to give status for this certificate" }, { 131, "The OCSP response is not yet valid (contains a date in the future)" }, { 132, "The OCSP response contains out-of-date information" }, { 133, "SEC_ERROR_DIGEST_NOT_FOUND - Digest not found in S/MIME message." }, { 134, "SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE - Unsupported or unknown message type in S/MIME message." }, { 135, "SEC_ERROR_MODULE_STUCK - PK11 module is stuck." }, { 136, "SEC_ERROR_BAD_TEMPLATE - Bad template found when decoding DER." }, { 137, "SEC_ERROR_CRL_NOT_FOUND" }, { 138, "SEC_ERROR_REUSED_ISSUER_AND_SERIAL" }, { 139, "SEC_ERROR_BUSY" }, { 140, "SEC_ERROR_EXTRA_INPUT" }, { 141, "SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE" }, { 142, "SEC_ERROR_UNSUPPORTED_EC_POINT_FORM" }, { 143, "SEC_ERROR_UNRECOGNIZED_OID" }, { 144, "SEC_ERROR_OCSP_INVALID_SIGNING_CERT - OCSP signer certificate not found, not trusted or invalid." }, { 145, "SEC_ERROR_REVOKED_CERTIFICATE_CRL - This certificate has been revoked." }, { 146, "SEC_ERROR_REVOKED_CERTIFICATE_OCSP - This certificate has been revoked." }, { 147, "SEC_ERROR_CRL_INVALID_VERSION" }, { 148, "SEC_ERROR_CRL_V1_CRITICAL_EXTENSION" }, { 149, "SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION" }, { 150, "SEC_ERROR_UNKNOWN_OBJECT_TYPE" }, { 151, "SEC_ERROR_INCOMPATIBLE_PKCS11" }, { 152, "SEC_ERROR_NO_EVENT" }, { 153, "SEC_ERROR_CRL_ALREADY_EXISTS" }, { 154, "SEC_ERROR_NOT_INITIALIZED" }, { 155, "SEC_ERROR_TOKEN_NOT_LOGGED_IN" } }; l_error_t libnss_errors[] = { { 0, "Client does not support high-grade encryption" }, { 1, "Client requires high-grade encryption which is not supported" }, { 2, "No common encryption algorithm(s) with client" }, { 3, "Unable to find the certificate or key necessary for authentication" }, { 4, "Unable to communicate securely wih peer: peer's certificate was rejected" }, { 5, "Unused SSL error #5" }, { 6, "Protocol error" }, { 7, "Protocol error" }, { 8, "Unsupported certificate type" }, { 9, "Client is using unsupported SSL version" }, { 10, "Unused SSL error #10" }, { 11, "The public key in the server's own certificate does not match its private key" }, { 12, "Requested domain name does not match the server's certificate" }, { 13, "SSL_ERROR_POST_WARNING" }, { 14, "peer only supports SSL version 2, which is locally disabled" }, { 15, "SSL has received a record with an incorrect Message Authentication Code" }, { 16, "SSL has received an error indicating an incorrect Message Authentication Code" }, { 17, "SSL client cannot verify your certificate" }, { 18, "The server has rejected your certificate as revoked" }, { 19, "The server has rejected your certificate as expired" }, { 20, "Cannot connect: SSL is disabled" }, { 21, "Cannot connect: SSL peer is in another Fortezza domain" }, { 22, "An unknown SSL cipher suite has been requested" }, { 23, "No cipher suites are present and enabled in this program" }, { 24, "SSL received a record with bad block padding" }, { 25, "SSL received a record that exceeded the maximum permissible length" }, { 26, "SSL attempted to send a record that exceeded the maximum permissible length" }, { 27, "SSL received a malformed Hello Request handshake message" }, { 28, "SSL received a malformed Client Hello handshake message" }, { 29, "SSL received a malformed Server Hello handshake message" }, { 30, "SSL received a malformed Certificate handshake message" }, { 31, "SSL received a malformed Server Key Exchange handshake message" }, { 32, "SSL received a malformed Certificate Request handshake message" }, { 33, "SSL received a malformed Server Hello Done handshake message" }, { 34, "SSL received a malformed Certificate Verify handshake message" }, { 35, "SSL received a malformed Client Key Exchange handshake message" }, { 36, "SSL received a malformed Finished handshake message" }, { 37, "SSL received a malformed Change Cipher Spec record" }, { 38, "SSL received a malformed Alert record" }, { 39, "SSL received a malformed Handshake record" }, { 40, "SSL received a malformed Application Data record" }, { 41, "SSL received an unexpected Hello Request handshake message" }, { 42, "SSL received an unexpected Client Hello handshake message" }, { 43, "SSL received an unexpected Server Hello handshake message" }, { 44, "SSL received an unexpected Certificate handshake message" }, { 45, "SSL received an unexpected Server Key Exchange handshake message" }, { 46, "SSL received an unexpected Certificate Request handshake message" }, { 47, "SSL received an unexpected Server Hello Done handshake message" }, { 48, "SSL received an unexpected Certificate Verify handshake message" }, { 49, "SSL received an unexpected Cllient Key Exchange handshake message" }, { 50, "SSL received an unexpected Finished handshake message" }, { 51, "SSL received an unexpected Change Cipher Spec record" }, { 52, "SSL received an unexpected Alert record" }, { 53, "SSL received an unexpected Handshake record" }, { 54, "SSL received an unexpected Application Data record" }, { 55, "SSL received a record with an unknown content type" }, { 56, "SSL received a handshake message with an unknown message type" }, { 57, "SSL received an alert record with an unknown alert description" }, { 58, "SSL peer has closed the connection" }, { 59, "SSL peer was not expecting a handshake message it received" }, { 60, "SSL peer was unable to succesfully decompress an SSL record it received" }, { 61, "SSL peer was unable to negotiate an acceptable set of security parameters" }, { 62, "SSL peer rejected a handshake message for unacceptable content" }, { 63, "SSL peer does not support certificates of the type it received" }, { 64, "SSL peer had some unspecified issue with the certificate it received" }, { 65, "SSL experienced a failure of its random number generator" }, { 66, "Unable to digitally sign data required to verify your certificate" }, { 67, "SSL was unable to extract the public key from the peer's certificate" }, { 68, "Unspecified failure while processing SSL Server Key Exchange handshake" }, { 69, "Unspecified failure while processing SSL Client Key Exchange handshake" }, { 70, "Bulk data encryption algorithm failed in selected cipher suite" }, { 71, "Bulk data decryption algorithm failed in selected cipher suite" }, { 72, "Attempt to write encrypted data to underlying socket failed" }, { 73, "MD5 digest function failed" }, { 74, "SHA-1 digest function failed" }, { 75, "MAC computation failed" }, { 76, "Failure to create Symmetric Key context" }, { 77, "Failure to unwrap the Symmetric key in Client Key Exchange message" }, { 78, "SSL Server attempted to use domestic-grade public key with export cipher suite" }, { 79, "PKCS11 code failed to translate an IV into a param" }, { 80, "Failed to initialize the selected cipher suite" }, { 81, "Failed to generate session keys for SSL session" }, { 82, "Server has no key for the attempted key exchange algorithm" }, { 83, "PKCS#11 token was inserted or removed while operation was in progress" }, { 84, "No PKCS#11 token could be found to do a required operation" }, { 85, "Cannot communicate securely with peer: no common compression algorithm(s)" }, { 86, "Cannot initiate another SSL handshake until current handshake is complete" }, { 87, "Received incorrect handshakes hash values from peer" }, { 88, "The certificate provided cannot be used with the selected key exchange algorithm" }, { 89, "There are no trusted Certificate Authorities for signing SSL client certificates" }, { 90, "Client's SSL session ID not found in server's session cache" }, { 91, "Peer was unable to decrypt an SSL record it received" }, { 92, "Peer received an SSL record that was longer than is permitted" }, { 93, "Peer does not recognize and trust the CA that issued your certificate" }, { 94, "Peer received a valid certificate, but access was denied" }, { 95, "Peer could not decode an SSL handshake message" }, { 96, "Peer reports failure of signature verification or key exchange" }, { 97, "Peer reports negotiation not in compliance with export regulations" }, { 98, "Peer reports incompatible or unsupported protocol version" }, { 99, "Server requires ciphers more secure than those supported by client" }, { 100, "Peer reports it experienced an internal error" }, { 101, "Peer user canceled handshake" }, { 102, "Peer does not permit renegotiation of SSL security parameters" }, { 103, "Server cache not configured" }, { 104, "Unsupported extension" }, { 105, "Certificate unobtainable" }, { 106, "Unrecognized name" }, { 107, "Bad certificate status" }, { 108, "Bad certificate hash value" }, { 109, "Unexpected new session ticket" }, { 110, "Malformed new session ticket" }, { 111, "Decompression failure" }, { 112, "Renegotiation not allowed" }, { 113, "Safe negotiation required but not provided by client" }, { 114, "Unexpected uncompressed record" }, }; void nss_die(void) { /* * This is used for fatal errors and here * it is common module practice to really * exit from the complete program. */ exit(1); } #if AP_SERVER_MINORVERSION_NUMBER <= 2 void nss_log_nss_error(const char *file, int line, int level, server_rec *s) #else void nss_log_nss_error(const char *file, int line, int module_index, int level, server_rec *s) #endif { const char *err; PRInt32 error; error = PR_GetError(); if ((error >= NSPR_ERROR_BASE) && (error <= NSPR_MAX_ERROR)) { return; /* We aren't logging NSPR errors */ } else if ((error >= LIBSEC_ERROR_BASE) && (error <= LIBSEC_MAX_ERROR)) { err = libsec_errors[error-LIBSEC_ERROR_BASE].errorString; } else if ((error >= LIBSSL_ERROR_BASE) && (error <= LIBSSL_MAX_ERROR)) { err = libnss_errors[error-LIBSSL_ERROR_BASE].errorString; } else { err = "Unknown"; } #if AP_SERVER_MINORVERSION_NUMBER <= 2 ap_log_error(file, line, level, 0, s, #else ap_log_error(file, line, module_index, level, 0, s, #endif "SSL Library Error: %d %s", error, err); } mod_nss-1.0.12/nss_engine_pcache.c000066400000000000000000000211321260357105600170400ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" /* * Mechanisms for doing the PIN encryption. Each of these lists * an encryption mechanism, with setup, encode and decode routines that * use that mechanism. The PK11PinStore looks for a mechanism * that the token supports, and then uses it. If none is found, * it will fail. */ typedef struct mech_item mech_item; struct mech_item { CK_MECHANISM_TYPE type; const char *mechName; }; /* * The table listing all mechanism to try */ #define MECH_TABLE_SIZE 4 static const mech_item table[MECH_TABLE_SIZE] = { { CKM_SKIPJACK_CBC64, "Skipjack CBC-64 encryption" }, { CKM_DES3_CBC, "Triple-DES CBC encryption" }, { CKM_CAST128_CBC, "CAST-128 CBC encryption" }, { CKM_DES_CBC, "DES CBC encryption" } }; static mech_item dflt_mech = { CKM_DES3_CBC, "Triple-DES CBC (default)" }; /* * Implementation */ struct Pk11PinStore { char *tokenName; mech_item *mech; SECItem *key; SECItem *params; int length; unsigned char *crypt; }; /* * CreatePk11PinStore */ SECStatus CreatePk11PinStore(apr_pool_t *pool, Pk11PinStore **out, const char *tokenName, const char *pin) { SECStatus err; Pk11PinStore *store; PK11SymKey *tmpkey; SECItem *tmpparams; PK11SlotInfo *slot; do { err = SECSuccess; store = (Pk11PinStore*)apr_pcalloc(pool, sizeof(Pk11PinStore)); if (store == 0) { err = SECFailure; break; } /* Low-level init */ store->tokenName = 0; store->key = 0; store->params = 0; store->crypt = 0; store->mech = (mech_item *)apr_pcalloc(pool, sizeof(mech_item)); /* Use the tokenName to find a PKCS11 slot */ slot = PK11_FindSlotByName((char *)tokenName); if (slot == 0) { err = SECFailure; break; } /* Check the password/PIN. This allows access to the token */ { SECStatus rv = PK11_CheckUserPassword(slot, (char *)pin); if (rv == SECSuccess) ; else if (rv == SECWouldBlock) { err = SECFailure; break; } else { err = SECFailure; break; } } store->tokenName = apr_pstrdup(pool, tokenName); /* Find the mechanism that this token can do */ { const mech_item *tp; for(tp = table;tp < &table[MECH_TABLE_SIZE];tp++) { if (PK11_DoesMechanism(slot, tp->type)) { // store->mech = tp; store->mech->type = tp->type; store->mech->mechName = apr_pstrdup(pool, tp->mechName); break; } } /* Default to a mechanism (probably on the internal token */ if (store->mech == 0) { // store->mech = &dflt_mech; store->mech->type = dflt_mech.type; store->mech->mechName = (char *)apr_pstrdup(pool, dflt_mech.mechName); } } /* Generate a key and parameters to do the encryption */ tmpkey = PK11_KeyGen(slot, store->mech->type, 0, 0, 0); if (tmpkey == 0) { /* PR_SetError(xxx); */ err = SECFailure; ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "key failed %d", PR_GetError()); break; } { SECItem *keydata = PK11_GetKeyData(tmpkey); store->key = (SECItem *)apr_pcalloc(pool, sizeof(SECItem)); store->key->type = keydata->type; store->key->len = keydata->len; store->key->data = apr_pcalloc(pool, keydata->len); memcpy(store->key->data, keydata->data, keydata->len); if (SECITEM_CompareItem(store->key, keydata) != SECEqual) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "key copy failed"); } tmpparams = PK11_GenerateNewParam(store->mech->type, tmpkey); if (tmpparams == 0) { err = SECFailure; break; } store->params = (SECItem *)apr_pcalloc(pool, sizeof(SECItem)); store->params->len = tmpparams->len; store->params->data = apr_pcalloc(pool, tmpparams->len); store->params->type = tmpparams->type; memcpy(store->params->data, tmpparams->data, tmpparams->len); if (SECITEM_CompareItem(store->params, tmpparams) != SECEqual) ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "params copy failed"); /* Compute the size of the encrypted data including necessary padding */ { int blocksize = PK11_GetBlockSize(store->mech->type, 0); store->length = strlen(pin)+1; /* Compute padded size - 0 means stream cipher */ if (blocksize != 0) { store->length += blocksize - (store->length % blocksize); } store->crypt = (unsigned char *)apr_pcalloc(pool, store->length); if (!store->crypt) { err = SECFailure; break; } } /* Encrypt */ { unsigned char *plain; PK11Context *ctx; SECStatus rv; int outLen; plain = (unsigned char *)malloc(store->length); if (!plain) { err = SECFailure; break; } /* Pad with 0 bytes */ memset(plain, 0, store->length); strcpy((char *)plain, pin); ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_ENCRYPT, tmpkey, store->params); if (!ctx) { err = SECFailure; break; } do { rv = PK11_CipherOp(ctx, store->crypt, &outLen, store->length, plain, store->length); if (rv) break; rv = PK11_Finalize(ctx); } while(0); PK11_DestroyContext(ctx, PR_TRUE); memset(plain, 0, store->length); free(plain); if (rv) err = SECFailure; } } while(0); if (err) { DestroyPk11PinStore(store); store = 0; } *out = store; return err; } /* * DestroyPk11PinStore */ void DestroyPk11PinStore(Pk11PinStore *store) { if (store == 0) return; if (store->params) { SECITEM_ZfreeItem(store->params, PR_TRUE); } if (store->crypt) { memset(store->crypt, 0, store->length); free(store->crypt); } free(store); } SECStatus Pk11StoreGetPin(char **out, Pk11PinStore *store) { SECStatus err = SECSuccess; unsigned char *plain; SECStatus rv; PK11Context *ctx = 0; int outLen; PK11SlotInfo *slot; PK11SymKey * tmpkey; do { plain = (unsigned char *)malloc(store->length); if (!plain) { err = SECFailure;ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "plain is null"); break; } slot = PK11_FindSlotByName(store->tokenName); ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "slot is %s param len is %d", store->tokenName, store->params->len); if (slot == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "no slot"); err=SECFailure;break; } tmpkey = PK11_KeyGen(slot, store->mech->type, store->key, 0, 0); ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_DECRYPT, tmpkey, store->params); if (!ctx) { err = SECFailure; ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "ctx is null %d", PR_GetError());break; } rv = PK11_CipherOp(ctx, plain, &outLen, store->length, store->crypt, store->length); if (rv) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "cipherop failed");break; } rv = PK11_Finalize(ctx); if (rv) break; } while(0); if (ctx) PK11_DestroyContext(ctx, PR_TRUE); if (rv) { err = SECFailure; memset(plain, 0, store->length); free(plain); plain = 0; } ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "plain is %s", plain); *out = (char *)plain; return err; } mod_nss-1.0.12/nss_engine_pphrase.c000066400000000000000000000310621260357105600172620ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" #include /* for echo on/off */ #include "nss_pcache.h" typedef struct { SSLModConfigRec *mc; PRInt32 retryCount; } pphrase_arg_t; static char * nss_password_prompt(PK11SlotInfo *slot, PRBool retry, void *arg); static char * nss_no_password(PK11SlotInfo *slot, PRBool retry, void *arg); static char * nss_get_password(FILE *input, FILE *output, PK11SlotInfo *slot, PRBool (*ok)(unsigned char *), pphrase_arg_t * parg); static PRBool nss_check_password(unsigned char *cp); static void echoOff(int fd); static void echoOn(int fd); /* * Global variables defined in this file. */ static char * prompt; /* * Initialize all SSL tokens. This involves authenticating the user * against the token password. It is possible that some tokens may * be authenticated and others will not be. */ SECStatus nss_Init_Tokens(server_rec *s) { PK11SlotList *slotList; PK11SlotListElement *listEntry; SECStatus ret, status = SECSuccess; SSLModConfigRec *mc = myModConfig(s); pphrase_arg_t * parg; parg = (pphrase_arg_t*)malloc(sizeof(*parg)); parg->mc = mc; parg->retryCount = 0; PK11_SetPasswordFunc(nss_password_prompt); slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL); for (listEntry = PK11_GetFirstSafe(slotList); listEntry; listEntry = listEntry->next) { PK11SlotInfo *slot = listEntry->slot; /* This is needed to work around a bug in NSS while in FIPS mode. * The first login will succeed but NSS_Shutdown() isn't cleaning * something up causing subsequent logins to be skipped making * keys and certs unavailable. */ PK11_Logout(slot); if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) { if (slot == PK11_GetInternalKeySlot()) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "The server key database has not been initialized."); } else { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "The token %s has not been initialized.", PK11_GetTokenName(slot)); } PK11_FreeSlot(slot); continue; } if (parg->mc->pphrase_dialog_type == SSL_PPTYPE_DEFER) { char * passwd = nss_get_password(stdin, stdout, slot, nss_check_password, parg); if (passwd == NULL) { PK11_FreeSlot(slot); continue; } free(passwd); } ret = PK11_Authenticate(slot, PR_TRUE, parg); if (SECSuccess != ret) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Password for slot %s is incorrect.", PK11_GetTokenName(slot)); PK11_FreeSlot(slot); /* We return here rather than breaking because: 1. All tokens must be logged for the server to work. 2. We'll get a bogus error message from nss_engine_init, -8053, instead of -8177. */ return SECFailure; } parg->retryCount = 0; /* reset counter to 0 for the next token */ PK11_FreeSlot(slot); } /* * reset NSS password callback to blank, so that the server won't prompt * again after initialization is done. */ PK11_SetPasswordFunc(nss_no_password); free(parg); return status; } /* * Wrapper callback function that prompts the user for the token password * up to 3 times. */ static char * nss_password_prompt(PK11SlotInfo *slot, PRBool retry, void *arg) { char *passwd = NULL; pphrase_arg_t *parg = (pphrase_arg_t *)arg; if (arg && retry) { parg->retryCount++; } prompt = PR_smprintf("Please enter password for \"%s\" token:", PK11_GetTokenName(slot)); if (parg == NULL) { /* should not happen */ passwd = nss_get_password(stdin, stdout, slot, nss_check_password, 0); } else { if (parg->retryCount > 2) { passwd = NULL; /* abort after 2 retries (3 failed attempts) */ } else { passwd = nss_get_password(stdin, stdout, slot, nss_check_password, parg); } } if ((parg->mc->nInitCount == 1) && (passwd != NULL)) { char buf[1024]; apr_status_t rv; apr_size_t nBytes = 1024; int res = PIN_SUCCESS; snprintf(buf, 1024, "STOR\t%s\t%s", PK11_GetTokenName(slot), passwd); rv = apr_file_write_full(parg->mc->proc.in, buf, strlen(buf), NULL); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Unable to write to pin store for slot: %s APR err: %d", PK11_GetTokenName(slot), rv); nss_die(); } /* Check the result. We don't really care what we got back as long * as the communication was successful. If the token password was * bad it will get handled later, we don't need to do anything * about it here. */ memset(buf, 0, sizeof(buf)); rv = apr_file_read(parg->mc->proc.out, buf, &nBytes); if (rv == APR_SUCCESS) res = atoi(buf); if (rv != APR_SUCCESS || (res != PIN_SUCCESS && res != PIN_INCORRECTPW)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Unable to read from pin store for slot: %s APR err: %d pcache: %d", PK11_GetTokenName(slot), rv, res); nss_die(); } } return passwd; } /* * Enforce basic password sanity rules on the password. We don't do * any actual enforcement here but it demonstrates the sorts of things * that may be done. */ static PRBool nss_check_password(unsigned char *cp) { int len; unsigned char *end, ch; len = strlen((char *)cp); if (len < 8) { return PR_TRUE; } end = cp + len; while (cp < end) { ch = *cp++; if (!((ch >= 'A') && (ch <= 'Z')) && !((ch >= 'a') && (ch <= 'z'))) { /* pass phrase has at least one non alphabetic in it */ return PR_TRUE; } } return PR_TRUE; } /* * Password callback so the user is not prompted to enter the password * after the server starts. */ static char * nss_no_password(PK11SlotInfo *slot, PRBool retry, void *arg) { return NULL; } /* * Password callback to prompt the user for a password. This requires * twiddling with the tty. Alternatively, if the file password.conf * exists then it may be used to store the token password(s). */ static char *nss_get_password(FILE *input, FILE *output, PK11SlotInfo *slot, PRBool (*ok)(unsigned char *), pphrase_arg_t *parg) { char *pwdstr = NULL; char *token_name = NULL; int tmp; FILE *pwd_fileptr; char *ptr; char line[1024]; unsigned char phrase[200]; int infd = fileno(input); int isTTY = isatty(infd); token_name = PK11_GetTokenName(slot); if (parg->mc->pphrase_dialog_type == SSL_PPTYPE_FILE || parg->mc->pphrase_dialog_type == SSL_PPTYPE_DEFER) { /* Try to get the passwords from the password file if it exists. * THIS IS UNSAFE and is provided for convenience only. Without this * capability the server would have to be started in foreground mode. */ if ((*parg->mc->pphrase_dialog_path != '\0') && ((pwd_fileptr = fopen(parg->mc->pphrase_dialog_path, "r")) != NULL)) { while(fgets(line, 1024, pwd_fileptr)) { if (PL_strstr(line, token_name) == line) { tmp = PL_strlen(line) - 1; while((line[tmp] == ' ') || (line[tmp] == '\n')) tmp--; line[tmp+1] = '\0'; ptr = PL_strchr(line, ':'); if (ptr == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Malformed password entry for token %s. Format should be token:password", token_name); continue; } for(tmp=1; ptr[tmp] == ' '; tmp++) {} pwdstr = strdup(&(ptr[tmp])); } } fclose(pwd_fileptr); } else { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Unable to open password file %s", parg->mc->pphrase_dialog_path); nss_die(); } } /* For SSL_PPTYPE_DEFER we only want to authenticate passwords found * in the password file. */ if ((parg->mc->pphrase_dialog_type == SSL_PPTYPE_DEFER) && (pwdstr == NULL)) { return NULL; } /* This purposely comes after the file check because that is more * authoritative. */ if (parg->mc->nInitCount > 1) { char buf[1024]; apr_status_t rv; apr_size_t nBytes = 1024; struct sembuf sb; /* lock the pipe */ sb.sem_num = 0; sb.sem_op = -1; sb.sem_flg = SEM_UNDO; if (semop(parg->mc->semid, &sb, 1) == -1) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Unable to reserve semaphore resource"); } snprintf(buf, 1024, "RETR\t%s", token_name); rv = apr_file_write_full(parg->mc->proc.in, buf, strlen(buf), NULL); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Unable to write to pin store for slot: %s APR err: %d", PK11_GetTokenName(slot), rv); nss_die(); } /* The helper just returns a token pw or "", so we don't have much * to check for. */ memset(buf, 0, sizeof(buf)); rv = apr_file_read(parg->mc->proc.out, buf, &nBytes); sb.sem_op = 1; if (semop(parg->mc->semid, &sb, 1) == -1) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Unable to free semaphore resource"); /* perror("semop free resource id"); */ } if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Unable to read from pin store for slot: %s APR err: %d", PK11_GetTokenName(slot), rv); nss_die(); } /* Just return what we got. If we got this far and we don't have a * PIN then I/O is already shut down, so we can't do anything really * clever. */ pwdstr = strdup(buf); } /* If we got a password we're done */ if (pwdstr) return pwdstr; for (;;) { /* Prompt for password */ if (isTTY) { if (parg->retryCount > 0) { fprintf(output, "Password incorrect. Please try again.\n"); } fprintf(output, "%s", prompt); echoOff(infd); } fgets((char*) phrase, sizeof(phrase), input); if (isTTY) { fprintf(output, "\n"); echoOn(infd); } /* stomp on newline */ phrase[strlen((char*)phrase)-1] = 0; /* Validate password */ if (!(*ok)(phrase)) { /* Not weird enough */ if (!isTTY) return 0; fprintf(output, "Password must be at least 8 characters long with one or more\n"); fprintf(output, "non-alphabetic characters\n"); continue; } if (PK11_IsFIPS() && strlen((char *)phrase) == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "The FIPS security policy requires that a password be set."); nss_die(); } else return (char*) PORT_Strdup((char*)phrase); } } /* * Turn the echoing off on a tty. */ static void echoOff(int fd) { if (isatty(fd)) { struct termios tio; tcgetattr(fd, &tio); tio.c_lflag &= ~ECHO; tcsetattr(fd, TCSAFLUSH, &tio); } } /* * Turn the echoing on on a tty. */ static void echoOn(int fd) { if (isatty(fd)) { struct termios tio; tcgetattr(fd, &tio); tio.c_lflag |= ECHO; tcsetattr(fd, TCSAFLUSH, &tio); } } mod_nss-1.0.12/nss_engine_rand.c000066400000000000000000000110561260357105600165450ustar00rootroot00000000000000/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" /* _________________________________________________________________ ** ** Support for better seeding of SSL library's RNG ** _________________________________________________________________ */ static int nss_rand_choosenum(int, int); static int nss_rand_feedfp(apr_pool_t *, apr_file_t *, int); int nss_rand_seed(server_rec *s, apr_pool_t *p, ssl_rsctx_t nCtx, char *prefix) { SSLModConfigRec *mc; apr_array_header_t *apRandSeed; ssl_randseed_t *pRandSeeds; ssl_randseed_t *pRandSeed; unsigned char stackdata[256]; int nReq, nDone; apr_file_t *fp; int i, n, l; mc = myModConfig(s); nReq = 0; nDone = 0; apRandSeed = mc->aRandSeed; pRandSeeds = (ssl_randseed_t *)apRandSeed->elts; for (i = 0; i < apRandSeed->nelts; i++) { pRandSeed = &pRandSeeds[i]; if (pRandSeed->nCtx == nCtx) { nReq += pRandSeed->nBytes; if (pRandSeed->nSrc == SSL_RSSRC_FILE) { /* * seed in contents of an external file */ if (apr_file_open(&fp, pRandSeed->cpPath, APR_READ, APR_OS_DEFAULT, p) != APR_SUCCESS) continue; nDone += nss_rand_feedfp(p, fp, pRandSeed->nBytes); apr_file_close(fp); } else if (pRandSeed->nSrc == SSL_RSSRC_EXEC) { const char *cmd = pRandSeed->cpPath; const char **argv = apr_palloc(p, sizeof(char *) * 3); /* * seed in contents generated by an external program */ argv[0] = cmd; argv[1] = apr_itoa(p, pRandSeed->nBytes); argv[2] = NULL; if ((fp = nss_util_ppopen(s, p, cmd, argv)) == NULL) continue; nDone += nss_rand_feedfp(p, fp, pRandSeed->nBytes); nss_util_ppclose(s, p, fp); } else if (pRandSeed->nSrc == SSL_RSSRC_BUILTIN) { struct { time_t t; pid_t pid; } my_seed; /* * seed in the current time (usually just 4 bytes) */ my_seed.t = time(NULL); /* * seed in the current process id (usually just 4 bytes) */ my_seed.pid = mc->pid; l = sizeof(my_seed); PK11_RandomUpdate((unsigned char *)&my_seed, l); nDone += l; /* * seed in some current state of the run-time stack (128 bytes) */ n = nss_rand_choosenum(0, sizeof(stackdata)-128-1); PK11_RandomUpdate(stackdata+n, 128); nDone += 128; } } } if (nDone > 0) ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "%sSeeding PRNG with %d bytes of entropy", prefix, nDone); return nDone; } #define BUFSIZE 8192 static int nss_rand_feedfp(apr_pool_t *p, apr_file_t *fp, int nReq) { apr_size_t nDone; unsigned char caBuf[BUFSIZE]; apr_size_t nBuf; apr_size_t nRead; apr_size_t nTodo; nDone = 0; nRead = BUFSIZE; nTodo = nReq; while (1) { if (nReq > 0) nRead = (nTodo < BUFSIZE ? nTodo : BUFSIZE); nBuf = nRead; if (apr_file_read(fp, caBuf, &nBuf) != APR_SUCCESS) break; PK11_RandomUpdate(caBuf, nBuf); nDone += nBuf; if (nReq > 0) { nTodo -= nBuf; if (nTodo <= 0) break; } } return nDone; } static int nss_rand_choosenum(int l, int h) { int i; char buf[50]; apr_snprintf(buf, sizeof(buf), "%.0f", (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l))); i = atoi(buf)+1; if (i < l) i = l; if (i > h) i = h; return i; } mod_nss-1.0.12/nss_engine_vars.c000066400000000000000000000652431260357105600166030ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" #include "secder.h" /* DER_GetInteger() */ #include "base64.h" /* BTOA_DataToAscii() */ #include "cert.h" /* CERT_* */ /* _________________________________________________________________ ** ** Variable Lookup ** _________________________________________________________________ */ #define CERT_NOTBEFORE 0 #define CERT_NOTAFTER 1 static char *nss_var_lookup_header(apr_pool_t *p, request_rec *r, const char *name); static char *nss_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var); static char *nss_var_lookup_nss_cert(apr_pool_t *p, CERTCertificate *xs, char *var, conn_rec *c); static char *nss_var_lookup_nss_cert_dn(apr_pool_t *p, CERTName *cert, char *var); static char *nss_var_lookup_nss_cert_valid(apr_pool_t *p, CERTCertificate *xs, int type); static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, CERTCertificate *xs); static char *nss_var_lookup_nss_cert_chain(apr_pool_t *p, CERTCertificate *cert,char *var); static char *nss_var_lookup_nss_cert_PEM(apr_pool_t *p, CERTCertificate *xs); static char *nss_var_lookup_nss_cert_verify(apr_pool_t *p, conn_rec *c); static char *nss_var_lookup_nss_cipher(apr_pool_t *p, conn_rec *c, char *var); static char *nss_var_lookup_nss_version(apr_pool_t *p, char *var); static char *nss_var_lookup_protocol_version(apr_pool_t *p, conn_rec *c); static char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var); static APR_OPTIONAL_FN_TYPE(ssl_is_https) *othermod_is_https; static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *othermod_var_lookup; static int nss_is_https(conn_rec *c) { SSLConnRec *sslconn = myConnConfig(c); return (sslconn && sslconn->ssl) || (othermod_is_https && othermod_is_https(c)); } static int ssl_is_https(conn_rec *c) { return nss_is_https(c); } void nss_var_register(void) { /* Always register these mod_nss optional functions */ APR_REGISTER_OPTIONAL_FN(nss_is_https); APR_REGISTER_OPTIONAL_FN(nss_var_lookup); /* Save the state of any previously registered mod_ssl functions */ othermod_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); othermod_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); /* Always register these local mod_ssl optional functions */ APR_REGISTER_OPTIONAL_FN(ssl_is_https); APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); return; } /* This function must remain safe to use for a non-SSL connection. */ char *nss_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var) { SSLModConfigRec *mc = myModConfig(s); char *result; BOOL resdup; apr_time_exp_t tm; result = NULL; resdup = TRUE; /* * When no pool is given try to find one */ if (p == NULL) { if (r != NULL) p = r->pool; else if (c != NULL) p = c->pool; else p = mc->pPool; } /* * Request dependent stuff */ if (r != NULL) { switch (var[0]) { case 'H': case 'h': if (strcEQ(var, "HTTP_USER_AGENT")) result = nss_var_lookup_header(p, r, "User-Agent"); else if (strcEQ(var, "HTTP_REFERER")) result = nss_var_lookup_header(p, r, "Referer"); else if (strcEQ(var, "HTTP_COOKIE")) result = nss_var_lookup_header(p, r, "Cookie"); else if (strcEQ(var, "HTTP_FORWARDED")) result = nss_var_lookup_header(p, r, "Forwarded"); else if (strcEQ(var, "HTTP_HOST")) result = nss_var_lookup_header(p, r, "Host"); else if (strcEQ(var, "HTTP_PROXY_CONNECTION")) result = nss_var_lookup_header(p, r, "Proxy-Connection"); else if (strcEQ(var, "HTTP_ACCEPT")) result = nss_var_lookup_header(p, r, "Accept"); else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5)) /* all other headers from which we are still not know about */ result = nss_var_lookup_header(p, r, var+5); break; case 'R': case 'r': if (strcEQ(var, "REQUEST_METHOD")) result = (char *)(r->method); else if (strcEQ(var, "REQUEST_SCHEME")) #if AP_SERVER_MINORVERSION_NUMBER < 2 /* See comment in mod_nss.h */ result = (char *)ap_http_method(r); #else result = (char *)ap_http_scheme(r); #endif else if (strcEQ(var, "REQUEST_URI")) result = r->uri; else if (strcEQ(var, "REQUEST_FILENAME")) result = r->filename; else if (strcEQ(var, "REMOTE_HOST")) result = (char *)ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME, NULL); else if (strcEQ(var, "REMOTE_IDENT")) result = (char *)ap_get_remote_logname(r); else if (strcEQ(var, "REMOTE_USER")) result = r->user; break; case 'S': case 's': if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */ if (strcEQ(var, "SERVER_ADMIN")) result = r->server->server_admin; else if (strcEQ(var, "SERVER_NAME")) result = (char *)ap_get_server_name(r); else if (strcEQ(var, "SERVER_PORT")) result = apr_psprintf(p, "%u", ap_get_server_port(r)); else if (strcEQ(var, "SERVER_PROTOCOL")) result = r->protocol; else if (strcEQ(var, "SCRIPT_FILENAME")) result = r->filename; break; default: if (strcEQ(var, "PATH_INFO")) result = r->path_info; else if (strcEQ(var, "QUERY_STRING")) result = r->args; else if (strcEQ(var, "IS_SUBREQ")) result = (r->main != NULL ? "true" : "false"); else if (strcEQ(var, "DOCUMENT_ROOT")) result = (char *)ap_document_root(r); else if (strcEQ(var, "AUTH_TYPE")) result = r->ap_auth_type; if (strcEQ(var, "THE_REQUEST")) result = r->the_request; break; } } /* * Connection stuff */ if (result == NULL && c != NULL) { SSLConnRec *sslconn = myConnConfig(c); if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) && (!sslconn || !sslconn->ssl) && othermod_var_lookup) { /* If mod_ssl is registered for this connection, * pass any SSL_* variable through to the mod_ssl module */ return othermod_var_lookup(p, s, c, r, var); } if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) && sslconn && sslconn->ssl) { result = nss_var_lookup_ssl(p, c, var+4); #ifdef VAR_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "%s: %s", var, result); #endif } else if (strcEQ(var, "REMOTE_ADDR")) #if AP_SERVER_MINORVERSION_NUMBER <= 2 result = c->remote_ip; #else result = c->client_ip; #endif else if (strcEQ(var, "HTTPS")) { if (sslconn && sslconn->ssl) result = "on"; else result = "off"; } } /* * Totally independent stuff */ if (result == NULL) { if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12)) result = nss_var_lookup_nss_version(p, var+12); else if (strcEQ(var, "SERVER_SOFTWARE")) result = (char *)ap_get_server_banner(); else if (strcEQ(var, "API_VERSION")) { result = apr_psprintf(p, "%d", MODULE_MAGIC_NUMBER); resdup = FALSE; } else if (strcEQ(var, "TIME_YEAR")) { apr_time_exp_lt(&tm, apr_time_now()); result = apr_psprintf(p, "%02d%02d", (tm.tm_year / 100) + 19, tm.tm_year % 100); resdup = FALSE; } #define MKTIMESTR(format, tmfield) \ apr_time_exp_lt(&tm, apr_time_now()); \ result = apr_psprintf(p, format, tm.tmfield); \ resdup = FALSE; else if (strcEQ(var, "TIME_MON")) { MKTIMESTR("%02d", tm_mon+1) } else if (strcEQ(var, "TIME_DAY")) { MKTIMESTR("%02d", tm_mday) } else if (strcEQ(var, "TIME_HOUR")) { MKTIMESTR("%02d", tm_hour) } else if (strcEQ(var, "TIME_MIN")) { MKTIMESTR("%02d", tm_min) } else if (strcEQ(var, "TIME_SEC")) { MKTIMESTR("%02d", tm_sec) } else if (strcEQ(var, "TIME_WDAY")) { MKTIMESTR("%d", tm_wday) } else if (strcEQ(var, "TIME")) { apr_time_exp_lt(&tm, apr_time_now()); result = apr_psprintf(p, "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19, (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); resdup = FALSE; } /* all other env-variables from the parent Apache process */ else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) { result = (char *)apr_table_get(r->notes, var+4); if (result == NULL) result = (char *)apr_table_get(r->subprocess_env, var+4); if (result == NULL) result = getenv(var+4); } } if (result != NULL && resdup) result = apr_pstrdup(p, result); if (result == NULL) result = ""; return result; } static char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var) { return nss_var_lookup(p, s, c, r, var); } static char *nss_var_lookup_header(apr_pool_t *p, request_rec *r, const char *name) { char *hdr = NULL; if ((hdr = (char *)apr_table_get(r->headers_in, name)) != NULL) hdr = apr_pstrdup(p, hdr); return hdr; } static char *nss_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var) { SSLConnRec *sslconn = myConnConfig(c); char *result; CERTCertificate *xs; PRFileDesc *ssl; result = NULL; ssl = sslconn->ssl; if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) { result = nss_var_lookup_nss_version(p, var+8); } else if (ssl != NULL && strcEQ(var, "PROTOCOL")) { result = (char *)nss_var_lookup_protocol_version(p, c); } else if (ssl != NULL && strcEQ(var, "SESSION_ID")) { char *idstr; SECItem *iditem; if ((iditem = SSL_GetSessionID(ssl)) == NULL) return NULL; /* Convert to base64 ASCII encoding */ idstr = BTOA_DataToAscii(iditem->data, iditem->len); if (idstr) { result = apr_pstrdup(p, idstr); PORT_Free(idstr); } SECITEM_FreeItem(iditem, PR_TRUE); } else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) { result = nss_var_lookup_nss_cipher(p, c, var+6); } else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) { xs = SSL_PeerCertificate(ssl); if (xs != NULL) { result = nss_var_lookup_nss_cert_chain(p, xs, var+18); CERT_DestroyCertificate(xs); } } else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) { result = nss_var_lookup_nss_cert_verify(p, c); } else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) { if ((xs = SSL_PeerCertificate(ssl)) != NULL) { result = nss_var_lookup_nss_cert(p, xs, var+7, c); CERT_DestroyCertificate(xs); } } else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) { if ((xs = SSL_LocalCertificate(ssl)) != NULL) { result = nss_var_lookup_nss_cert(p, xs, var+7, c); CERT_DestroyCertificate(xs); } } else if (ssl != NULL && strcEQ(var, "TLS_SNI")) { SECItem *hostInfo = SSL_GetNegotiatedHostInfo(ssl); if (hostInfo) { result = apr_pstrndup(p, (char *) hostInfo->data, hostInfo->len); PORT_Free(hostInfo); } } else if (ssl != NULL && strcEQ(var, "SECURE_RENEG")) { PRInt32 flag = 0; #ifdef SSL_ENABLE_RENEGOTIATION SSL_OptionGet(ssl, SSL_ENABLE_RENEGOTIATION, &flag); #endif result = apr_pstrdup(p, flag ? "true" : "false"); } return result; } static char *nss_var_lookup_nss_cert(apr_pool_t *p, CERTCertificate *xs, char *var, conn_rec *c) { char *result; BOOL resdup; char *xsname; result = NULL; resdup = TRUE; if (strcEQ(var, "M_VERSION")) { if (xs->version.data != NULL) { result = apr_psprintf(p, "%lu", DER_GetInteger(&xs->version)+1); resdup = FALSE; } else { result = apr_pstrdup(p, "UNKNOWN"); resdup = FALSE; } } else if (strcEQ(var, "M_SERIAL")) { result = apr_psprintf(p, "%lu", DER_GetInteger(&xs->serialNumber)); resdup = FALSE; } else if (strcEQ(var, "V_START")) { result = nss_var_lookup_nss_cert_valid(p, xs, CERT_NOTBEFORE); } else if (strcEQ(var, "V_END")) { result = nss_var_lookup_nss_cert_valid(p, xs, CERT_NOTAFTER); } else if (strcEQ(var, "V_REMAIN")) { result = ssl_var_lookup_ssl_cert_remain(p, xs); resdup = FALSE; } else if (strcEQ(var, "S_DN")) { xsname = CERT_NameToAscii(&xs->subject); result = apr_pstrdup(p, xsname); PORT_Free(xsname); resdup = FALSE; } else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) { result = nss_var_lookup_nss_cert_dn(p, &xs->subject, var+5); resdup = FALSE; } else if (strcEQ(var, "I_DN")) { xsname = CERT_NameToAscii(&xs->issuer); result = apr_pstrdup(p, xsname); PORT_Free(xsname); resdup = FALSE; } else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) { result = nss_var_lookup_nss_cert_dn(p, &xs->issuer, var+5); resdup = FALSE; } else if (strcEQ(var, "A_SIG")) { SSLChannelInfo channel; SSLCipherSuiteInfo suite; SSLConnRec *sslconn = myConnConfig(c); if (SSL_GetChannelInfo(sslconn->ssl, &channel, sizeof channel) == SECSuccess && channel.length == sizeof channel && channel.cipherSuite) { if (SSL_GetCipherSuiteInfo(channel.cipherSuite, &suite, sizeof suite) == SECSuccess) { result = apr_psprintf(p, "%s-%s", suite.macAlgorithmName, suite.authAlgorithmName); } } else result = apr_pstrdup(p, "UNKNOWN"); resdup = FALSE; } else if (strcEQ(var, "A_KEY")) { SSLChannelInfo channel; SSLCipherSuiteInfo suite; SSLConnRec *sslconn = myConnConfig(c); if (SSL_GetChannelInfo(sslconn->ssl, &channel, sizeof channel) == SECSuccess && channel.length == sizeof channel && channel.cipherSuite) { if (SSL_GetCipherSuiteInfo(channel.cipherSuite, &suite, sizeof suite) == SECSuccess) { result = apr_psprintf(p, "%s_%s", suite.keaTypeName, suite.authAlgorithmName); } } else result = apr_pstrdup(p, "UNKNOWN_UNKNOWN"); resdup = FALSE; } else if (strcEQ(var, "CERT")) { result = nss_var_lookup_nss_cert_PEM(p, xs); } if (result != NULL && resdup) result = apr_pstrdup(p, result); return result; } static char *nss_var_lookup_nss_cert_dn(apr_pool_t *p, CERTName *cert, char *var) { char *result; char *rv; result = NULL; rv = NULL; if (strcEQ(var, "C")) { rv = CERT_GetCountryName(cert); } else if (strcEQ(var, "ST")) { rv = CERT_GetStateName(cert); } else if (strcEQ(var, "SP")) { /* for compatibility */ rv = CERT_GetStateName(cert); } else if (strcEQ(var, "L")) { rv = CERT_GetLocalityName(cert); } else if (strcEQ(var, "O")) { rv = CERT_GetOrgName(cert); } else if (strcEQ(var, "OU")) { rv = CERT_GetOrgUnitName(cert); } else if (strcEQ(var, "CN")) { rv = CERT_GetCommonName(cert); } else if (strcEQ(var, "UID")) { rv = CERT_GetCertUid(cert); } else if (strcEQ(var, "EMAIL")) { rv = CERT_GetCertEmailAddress(cert); } else { rv = NULL; /* catch any values we don't support */ } if (rv) { result = apr_pstrdup(p, rv); PORT_Free(rv); /* so we can free with the right allocator */ } return result; } static char *nss_var_lookup_nss_cert_valid(apr_pool_t *p, CERTCertificate *xs, int type) { char *result; PRExplodedTime printableTime; char timeString[256]; PRTime notBefore, notAfter; CERT_GetCertTimes(xs, ¬Before, ¬After); /* Converse time to local time and decompose it into components */ if (type == CERT_NOTBEFORE) { PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime); } else { PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime); } PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); result = apr_pstrdup(p, timeString); return result; } /* Return a string giving the number of days remaining until the cert * expires "0" if this can't be determined. * * In mod_ssl this is more generic, passing in a time to calculate against, * but I see no point in converting the end date into a string and back again. */ static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, CERTCertificate *xs) { PRTime notBefore, notAfter; PRTime now, diff; CERT_GetCertTimes(xs, ¬Before, ¬After); now = PR_Now(); /* Both times are relative to the epoch, so no TZ calcs are needed */ diff = notAfter - now; /* PRTime is in microseconds so convert to seconds before days */ diff = (diff / PR_USEC_PER_SEC) / (60*60*24); return (diff > 0) ? apr_itoa(p, diff) : apr_pstrdup(p, "0"); } static char *nss_var_lookup_nss_cert_chain(apr_pool_t *p, CERTCertificate *cert, char *var) { char *result; CERTCertificateList *chain = NULL; int n; result = NULL; chain = CERT_CertChainFromCert(cert, certUsageSSLClient, PR_TRUE); if (!chain) return NULL; if (strspn(var, "0123456789") == strlen(var)) { n = atoi(var); if (n <= chain->len-1) { CERTCertificate *c; c = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), &chain->certs[n]); result = nss_var_lookup_nss_cert_PEM(p, c); CERT_DestroyCertificate(c); } } CERT_DestroyCertificateList(chain); return result; } #define CERT_HEADER "-----BEGIN CERTIFICATE-----\n" #define CERT_TRAILER "\n-----END CERTIFICATE-----\n" static char *nss_var_lookup_nss_cert_PEM(apr_pool_t *p, CERTCertificate *xs) { char * result = NULL; char * tmp = NULL; int i, len; /* should never happen but we'll crash if it does */ if (!xs) return NULL; tmp = BTOA_DataToAscii(xs->derCert.data, xs->derCert.len); /* NSS uses \r\n as the line terminator. Remove \r so the output is * similar to mod_ssl. */ i=0; len = strlen(tmp); for (i=0; i < len; i++) { if (tmp[i] == '\r') { memmove(&tmp[i], &tmp[i+1], 1+(len - i - 1)); } i++; } result = apr_pstrcat(p, CERT_HEADER, tmp, CERT_TRAILER, NULL); /* Clean up memory. */ PORT_Free(tmp); return result; } static char *nss_var_lookup_nss_cert_verify(apr_pool_t *p, conn_rec *c) { SSLConnRec *sslconn = myConnConfig(c); char *result; PRFileDesc *ssl; SECStatus rv; CERTCertificate *xs; void *pinArg; result = NULL; ssl = sslconn->ssl; xs = SSL_PeerCertificate(ssl); pinArg = SSL_RevealPinArg(sslconn->ssl); if (xs == NULL) result = "NONE"; else { rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), xs, PR_TRUE, certUsageSSLClient, pinArg); if (rv == SECSuccess) result = "SUCCESS"; else result = apr_psprintf(p, "FAILED"); /* FIXME, add more info? */ } if (xs) CERT_DestroyCertificate(xs); return result; } static char *nss_var_lookup_nss_cipher(apr_pool_t *p, conn_rec *c, char *var) { SSLConnRec *sslconn = myConnConfig(c); char *result; BOOL resdup; PRFileDesc *ssl; int on, keySize, secretKeySize; char *cipher, *issuer, *subject; SECStatus secstatus = SECFailure; result = NULL; resdup = TRUE; on = keySize = secretKeySize = 0; cipher = issuer = subject = NULL; ssl = sslconn->ssl; if (ssl) { secstatus = SSL_SecurityStatus(ssl, &on, &cipher, &keySize, &secretKeySize, &issuer, &subject); } if (secstatus != SECSuccess) return NULL; if (ssl && strEQ(var, "")) { result = cipher; } else if (strcEQ(var, "_EXPORT")) result = (secretKeySize < 56 ? "true" : "false"); else if (strcEQ(var, "_USEKEYSIZE")) { result = apr_psprintf(p, "%d", secretKeySize); resdup = FALSE; } else if (strcEQ(var, "_ALGKEYSIZE")) { result = apr_psprintf(p, "%d", keySize); resdup = FALSE; } else if (strcEQ(var, "_NAME")) { SSLChannelInfo channel; SSLCipherSuiteInfo suite; SSLConnRec *sslconn = myConnConfig(c); if (SSL_GetChannelInfo(sslconn->ssl, &channel, sizeof channel) == SECSuccess && channel.length == sizeof channel && channel.cipherSuite) { if (SSL_GetCipherSuiteInfo(channel.cipherSuite, &suite, sizeof suite) == SECSuccess) { result = apr_psprintf(p, "%s", suite.cipherSuiteName); } } else result = apr_pstrdup(p, "UNKNOWN"); resdup = FALSE; } if (result != NULL && resdup) result = apr_pstrdup(p, result); PORT_Free(issuer); PORT_Free(subject); PORT_Free(cipher); return result; } static char *nss_var_lookup_nss_version(apr_pool_t *p, char *var) { char *result; result = NULL; if (strEQ(var, "PRODUCT")) { #if defined(SSL_PRODUCT_NAME) && defined(SSL_PRODUCT_VERSION) result = apr_psprintf(p, "%s/%s", SSL_PRODUCT_NAME, SSL_PRODUCT_VERSION); #else result = NULL; #endif } else if (strEQ(var, "INTERFACE")) { result = apr_psprintf(p, "mod_nss/%s", MOD_NSS_VERSION); } else if (strEQ(var, "LIBRARY")) { result = apr_psprintf(p, "NSS/%s", NSS_VERSION); } return result; } static char *nss_var_lookup_protocol_version(apr_pool_t *p, conn_rec *c) { char *result; SSLChannelInfo channel; SSLCipherSuiteInfo suite; SSLConnRec *sslconn = myConnConfig(c); result = "UNKNOWN"; if (SSL_GetChannelInfo(sslconn->ssl, &channel, sizeof channel) == SECSuccess && channel.length == sizeof channel && channel.cipherSuite) { if (SSL_GetCipherSuiteInfo(channel.cipherSuite, &suite, sizeof suite) == SECSuccess) { switch (channel.protocolVersion) { case SSL_LIBRARY_VERSION_2: result = "SSLv2"; break; case SSL_LIBRARY_VERSION_3_0: result = "SSLv3"; break; case SSL_LIBRARY_VERSION_TLS_1_0: /* 'TLSv1' has been deprecated; specify 'TLSv1.0' */ result = "TLSv1"; break; case SSL_LIBRARY_VERSION_TLS_1_1: result = "TLSv1.1"; break; case SSL_LIBRARY_VERSION_TLS_1_2: result = "TLSv1.2"; break; } } } result = apr_pstrdup(p, result); return result; } /* _________________________________________________________________ ** ** SSL Extension to mod_log_config ** _________________________________________________________________ */ #include "mod_log_config.h" static const char *nss_var_log_handler_c(request_rec *r, char *a); static const char *nss_var_log_handler_x(request_rec *r, char *a); /* * register us for the mod_log_config function registering phase * to establish %{...}c and to be able to expand %{...}x variables. */ void nss_var_log_config_register(apr_pool_t *p) { static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register; log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); if (log_pfn_register) { log_pfn_register(p, "c", nss_var_log_handler_c, 0); log_pfn_register(p, "x", nss_var_log_handler_x, 0); } return; } /* * implement the %{..}c log function * (we are the only function) */ static const char *nss_var_log_handler_c(request_rec *r, char *a) { SSLConnRec *sslconn = myConnConfig(r->connection); char *result; if (sslconn == NULL || sslconn->ssl == NULL) return NULL; result = NULL; if (strEQ(a, "version")) result = nss_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL"); else if (strEQ(a, "cipher")) result = nss_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER"); else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert")) result = nss_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN"); else if (strEQ(a, "issuerdn") || strEQ(a, "cacert")) result = nss_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN"); else if (strEQ(a, "errcode")) result = "-"; if (result != NULL && result[0] == NUL) result = NULL; return result; } /* * extend the implementation of the %{..}x log function * (there can be more functions) */ static const char *nss_var_log_handler_x(request_rec *r, char *a) { char *result; result = nss_var_lookup(r->pool, r->server, r->connection, r, a); if (result != NULL && result[0] == NUL) result = NULL; return result; } mod_nss-1.0.12/nss_expr.c000066400000000000000000000034521260357105600152530ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" /* _________________________________________________________________ ** ** Expression Handling ** _________________________________________________________________ */ nss_expr_info_type nss_expr_info; char *nss_expr_error; nss_expr *nss_expr_comp(apr_pool_t *p, char *expr) { nss_expr_info.pool = p; nss_expr_info.inputbuf = expr; nss_expr_info.inputlen = strlen(expr); nss_expr_info.inputptr = nss_expr_info.inputbuf; nss_expr_info.expr = FALSE; nss_expr_error = NULL; if (nss_expr_yyparse()) return NULL; return nss_expr_info.expr; } char *nss_expr_get_error(void) { if (nss_expr_error == NULL) return ""; return nss_expr_error; } nss_expr *nss_expr_make(nss_expr_node_op op, void *a1, void *a2) { nss_expr *node; node = (nss_expr *)apr_palloc(nss_expr_info.pool, sizeof(nss_expr)); node->node_op = op; node->node_arg1 = (char *)a1; node->node_arg2 = (char *)a2; return node; } int nss_expr_exec(request_rec *r, nss_expr *expr) { BOOL rc; rc = nss_expr_eval(r, expr); if (nss_expr_error != NULL) return (-1); else return (rc ? 1 : 0); } mod_nss-1.0.12/nss_expr.h000066400000000000000000000041431260357105600152560ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __NSS_EXPR_H__ #define __NSS_EXPR_H__ #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE !FALSE #endif #ifndef YY_NULL #define YY_NULL 0 #endif #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef BOOL #define BOOL unsigned int #endif #ifndef NULL #define NULL (void *)0 #endif #ifndef NUL #define NUL '\0' #endif #ifndef YYDEBUG #define YYDEBUG 0 #endif typedef enum { op_NOP, op_ListElement, op_True, op_False, op_Not, op_Or, op_And, op_Comp, op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN, op_REG, op_NRE, op_Digit, op_String, op_Regex, op_Var, op_Func } nss_expr_node_op; typedef struct { nss_expr_node_op node_op; void *node_arg1; void *node_arg2; apr_pool_t *p; } nss_expr_node; typedef nss_expr_node nss_expr; typedef struct { apr_pool_t *pool; char *inputbuf; int inputlen; char *inputptr; nss_expr *expr; } nss_expr_info_type; extern nss_expr_info_type nss_expr_info; extern char *nss_expr_error; #define yylval nss_expr_yylval #define yyerror nss_expr_yyerror #define yyinput nss_expr_yyinput extern int nss_expr_yyparse(void); extern int nss_expr_yyerror(char *); extern int nss_expr_yylex(void); extern nss_expr *nss_expr_comp(apr_pool_t *, char *); extern int nss_expr_exec(request_rec *, nss_expr *); extern char *nss_expr_get_error(void); extern nss_expr *nss_expr_make(nss_expr_node_op, void *, void *); extern BOOL nss_expr_eval(request_rec *, nss_expr *); #endif /* __NSS_EXPR_H__ */ mod_nss-1.0.12/nss_expr_eval.c000066400000000000000000000175161260357105600162700ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" /* _________________________________________________________________ ** ** Expression Evaluation ** _________________________________________________________________ */ static BOOL nss_expr_eval_comp(request_rec *, nss_expr *); static char *nss_expr_eval_word(request_rec *, nss_expr *); static char *nss_expr_eval_func_file(request_rec *, char *); static int nss_expr_eval_strcmplex(char *, char *); BOOL nss_expr_eval(request_rec *r, nss_expr *node) { switch (node->node_op) { case op_True: { return TRUE; } case op_False: { return FALSE; } case op_Not: { nss_expr *e = (nss_expr *)node->node_arg1; return (!nss_expr_eval(r, e)); } case op_Or: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; return (nss_expr_eval(r, e1) || nss_expr_eval(r, e2)); } case op_And: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; return (nss_expr_eval(r, e1) && nss_expr_eval(r, e2)); } case op_Comp: { nss_expr *e = (nss_expr *)node->node_arg1; return nss_expr_eval_comp(r, e); } default: { nss_expr_error = "Internal evaluation error: Unknown expression node"; return FALSE; } } } static BOOL nss_expr_eval_comp(request_rec *r, nss_expr *node) { switch (node->node_op) { case op_EQ: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; return (strcmp(nss_expr_eval_word(r, e1), nss_expr_eval_word(r, e2)) == 0); } case op_NE: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; return (strcmp(nss_expr_eval_word(r, e1), nss_expr_eval_word(r, e2)) != 0); } case op_LT: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; return (nss_expr_eval_strcmplex(nss_expr_eval_word(r, e1), nss_expr_eval_word(r, e2)) < 0); } case op_LE: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; return (nss_expr_eval_strcmplex(nss_expr_eval_word(r, e1), nss_expr_eval_word(r, e2)) <= 0); } case op_GT: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; return (nss_expr_eval_strcmplex(nss_expr_eval_word(r, e1), nss_expr_eval_word(r, e2)) > 0); } case op_GE: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; return (nss_expr_eval_strcmplex(nss_expr_eval_word(r, e1), nss_expr_eval_word(r, e2)) >= 0); } case op_IN: { nss_expr *e1 = (nss_expr *)node->node_arg1; nss_expr *e2 = (nss_expr *)node->node_arg2; nss_expr *e3; char *w1 = nss_expr_eval_word(r, e1); BOOL found = FALSE; do { e3 = (nss_expr *)e2->node_arg1; e2 = (nss_expr *)e2->node_arg2; if (strcmp(w1, nss_expr_eval_word(r, e3)) == 0) { found = TRUE; break; } } while (e2 != NULL); return found; } case op_REG: { nss_expr *e1; nss_expr *e2; char *word; ap_regex_t *regex; e1 = (nss_expr *)node->node_arg1; e2 = (nss_expr *)node->node_arg2; word = nss_expr_eval_word(r, e1); regex = (ap_regex_t *)(e2->node_arg1); return (ap_regexec(regex, word, 0, NULL, 0) == 0); } case op_NRE: { nss_expr *e1; nss_expr *e2; char *word; ap_regex_t *regex; e1 = (nss_expr *)node->node_arg1; e2 = (nss_expr *)node->node_arg2; word = nss_expr_eval_word(r, e1); regex = (ap_regex_t *)(e2->node_arg1); return !(ap_regexec(regex, word, 0, NULL, 0) == 0); } default: { nss_expr_error = "Internal evaluation error: Unknown expression node"; return FALSE; } } } static char *nss_expr_eval_word(request_rec *r, nss_expr *node) { switch (node->node_op) { case op_Digit: { char *string = (char *)node->node_arg1; return string; } case op_String: { char *string = (char *)node->node_arg1; return string; } case op_Var: { char *var = (char *)node->node_arg1; char *val = nss_var_lookup(r->pool, r->server, r->connection, r, var); return (val == NULL ? "" : val); } case op_Func: { char *name = (char *)node->node_arg1; nss_expr *args = (nss_expr *)node->node_arg2; if (strEQ(name, "file")) return nss_expr_eval_func_file(r, (char *)(args->node_arg1)); else { nss_expr_error = "Internal evaluation error: Unknown function name"; return ""; } } default: { nss_expr_error = "Internal evaluation error: Unknown expression node"; return FALSE; } } } static char *nss_expr_eval_func_file(request_rec *r, char *filename) { apr_file_t *fp; char *buf; apr_off_t offset; apr_size_t len; apr_finfo_t finfo; if (apr_file_open(&fp, filename, APR_READ|APR_BUFFERED, APR_OS_DEFAULT, r->pool) != APR_SUCCESS) { nss_expr_error = "Cannot open file"; return ""; } apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); if ((finfo.size + 1) != ((apr_size_t)finfo.size + 1)) { nss_expr_error = "Huge file cannot be read"; apr_file_close(fp); return ""; } len = (apr_size_t)finfo.size; if (len == 0) { buf = (char *)apr_palloc(r->pool, sizeof(char) * 1); *buf = NUL; } else { if ((buf = (char *)apr_palloc(r->pool, sizeof(char)*(len+1))) == NULL) { nss_expr_error = "Cannot allocate memory"; apr_file_close(fp); return ""; } offset = 0; apr_file_seek(fp, APR_SET, &offset); if (apr_file_read(fp, buf, &len) != APR_SUCCESS) { nss_expr_error = "Cannot read from file"; apr_file_close(fp); return ""; } buf[len] = NUL; } apr_file_close(fp); return buf; } /* a variant of strcmp(3) which works correctly also for number strings */ static int nss_expr_eval_strcmplex(char *cpNum1, char *cpNum2) { int i, n1, n2; if (cpNum1 == NULL) return -1; if (cpNum2 == NULL) return +1; n1 = strlen(cpNum1); n2 = strlen(cpNum2); if (n1 > n2) return 1; if (n1 < n2) return -1; for (i = 0; i < n1; i++) { if (cpNum1[i] > cpNum2[i]) return 1; if (cpNum1[i] < cpNum2[i]) return -1; } return 0; } mod_nss-1.0.12/nss_expr_parse.c000066400000000000000000001257461260357105600164600ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 1.875c. */ /* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* Written by Richard Stallman by simplifying the original so called ``semantic'' parser. */ /* All symbols defined below should begin with nss_expr_yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Using locations. */ #define YYLSP_NEEDED 0 /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum nss_expr_yytokentype { T_TRUE = 258, T_FALSE = 259, T_DIGIT = 260, T_ID = 261, T_STRING = 262, T_REGEX = 263, T_REGEX_I = 264, T_FUNC_FILE = 265, T_OP_EQ = 266, T_OP_NE = 267, T_OP_LT = 268, T_OP_LE = 269, T_OP_GT = 270, T_OP_GE = 271, T_OP_REG = 272, T_OP_NRE = 273, T_OP_IN = 274, T_OP_OR = 275, T_OP_AND = 276, T_OP_NOT = 277 }; #endif #define T_TRUE 258 #define T_FALSE 259 #define T_DIGIT 260 #define T_ID 261 #define T_STRING 262 #define T_REGEX 263 #define T_REGEX_I 264 #define T_FUNC_FILE 265 #define T_OP_EQ 266 #define T_OP_NE 267 #define T_OP_LT 268 #define T_OP_LE 269 #define T_OP_GT 270 #define T_OP_GE 271 #define T_OP_REG 272 #define T_OP_NRE 273 #define T_OP_IN 274 #define T_OP_OR 275 #define T_OP_AND 276 #define T_OP_NOT 277 /* Copy the first part of user declarations. */ #line 22 "nss_expr_parse.y" #include "mod_nss.h" /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) #line 26 "nss_expr_parse.y" typedef union YYSTYPE { char *cpVal; nss_expr *exVal; } YYSTYPE; /* Line 191 of yacc.c. */ #line 129 "y.tab.c" # define nss_expr_yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif /* Copy the second part of user declarations. */ /* Line 214 of yacc.c. */ #line 141 "y.tab.c" #if ! defined (nss_expr_yyoverflow) || YYERROR_VERBOSE # ifndef YYFREE # define YYFREE free # endif # ifndef YYMALLOC # define YYMALLOC malloc # endif /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # define YYSTACK_ALLOC alloca # endif # else # if defined (alloca) || defined (_ALLOCA_H) # define YYSTACK_ALLOC alloca # else # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # else # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # endif #endif /* ! defined (nss_expr_yyoverflow) || YYERROR_VERBOSE */ #if (! defined (nss_expr_yyoverflow) \ && (! defined (__cplusplus) \ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union nss_expr_yyalloc { short nss_expr_yyss; YYSTYPE nss_expr_yyvs; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union nss_expr_yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined (__GNUC__) && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ register YYSIZE_T nss_expr_yyi; \ for (nss_expr_yyi = 0; nss_expr_yyi < (Count); nss_expr_yyi++) \ (To)[nss_expr_yyi] = (From)[nss_expr_yyi]; \ } \ while (0) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T nss_expr_yynewbytes; \ YYCOPY (&nss_expr_yyptr->Stack, Stack, nss_expr_yysize); \ Stack = &nss_expr_yyptr->Stack; \ nss_expr_yynewbytes = nss_expr_yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ nss_expr_yyptr += nss_expr_yynewbytes / sizeof (*nss_expr_yyptr); \ } \ while (0) #endif #if defined (__STDC__) || defined (__cplusplus) typedef signed char nss_expr_yysigned_char; #else typedef short nss_expr_yysigned_char; #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 18 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 52 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 29 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 8 /* YYNRULES -- Number of rules. */ #define YYNRULES 27 /* YYNRULES -- Number of states. */ #define YYNSTATES 53 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 277 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? nss_expr_yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const unsigned char nss_expr_yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 23, 24, 2, 2, 27, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 25, 2, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const unsigned char nss_expr_yyprhs[] = { 0, 0, 3, 5, 7, 9, 12, 16, 20, 22, 26, 30, 34, 38, 42, 46, 50, 56, 60, 64, 66, 70, 72, 74, 79, 81, 83, 85 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const nss_expr_yysigned_char nss_expr_yyrhs[] = { 30, 0, -1, 31, -1, 3, -1, 4, -1, 22, 31, -1, 31, 20, 31, -1, 31, 21, 31, -1, 32, -1, 23, 31, 24, -1, 34, 11, 34, -1, 34, 12, 34, -1, 34, 13, 34, -1, 34, 14, 34, -1, 34, 15, 34, -1, 34, 16, 34, -1, 34, 19, 25, 33, 26, -1, 34, 17, 35, -1, 34, 18, 35, -1, 34, -1, 33, 27, 34, -1, 5, -1, 7, -1, 28, 25, 6, 26, -1, 36, -1, 8, -1, 9, -1, 10, 23, 7, 24, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const unsigned char nss_expr_yyrline[] = { 0, 69, 69, 72, 73, 74, 75, 76, 77, 78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 93, 96, 97, 98, 99, 102, 111, 122 }; #endif #if YYDEBUG || YYERROR_VERBOSE /* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const nss_expr_yytname[] = { "$end", "error", "$undefined", "T_TRUE", "T_FALSE", "T_DIGIT", "T_ID", "T_STRING", "T_REGEX", "T_REGEX_I", "T_FUNC_FILE", "T_OP_EQ", "T_OP_NE", "T_OP_LT", "T_OP_LE", "T_OP_GT", "T_OP_GE", "T_OP_REG", "T_OP_NRE", "T_OP_IN", "T_OP_OR", "T_OP_AND", "T_OP_NOT", "'('", "')'", "'{'", "'}'", "','", "'%'", "$accept", "root", "expr", "comparison", "words", "word", "regex", "funccall", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const unsigned short nss_expr_yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 40, 41, 123, 125, 44, 37 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const unsigned char nss_expr_yyr1[] = { 0, 29, 30, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const unsigned char nss_expr_yyr2[] = { 0, 2, 1, 1, 1, 2, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 1, 3, 1, 1, 4, 1, 1, 1, 4 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const unsigned char nss_expr_yydefact[] = { 0, 3, 4, 21, 22, 0, 0, 0, 0, 0, 2, 8, 0, 24, 0, 5, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 6, 7, 10, 11, 12, 13, 14, 15, 25, 26, 17, 18, 0, 27, 23, 0, 19, 16, 0, 20 }; /* YYDEFGOTO[NTERM-NUM]. */ static const nss_expr_yysigned_char nss_expr_yydefgoto[] = { -1, 9, 10, 11, 48, 12, 43, 13 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -22 static const nss_expr_yysigned_char nss_expr_yypact[] = { 3, -22, -22, -22, -22, -11, 3, 3, 2, 44, -1, -22, 22, -22, 38, -22, -3, 40, -22, 3, 3, 4, 4, 4, 4, 4, 4, 14, 14, 23, 25, -22, 21, 29, -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, 4, -22, -22, 16, -22, -22, 4, -22 }; /* YYPGOTO[NTERM-NUM]. */ static const nss_expr_yysigned_char nss_expr_yypgoto[] = { -22, -22, 9, -22, -22, -21, 24, -22 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 static const unsigned char nss_expr_yytable[] = { 35, 36, 37, 38, 39, 40, 1, 2, 3, 3, 4, 4, 14, 5, 5, 15, 16, 19, 20, 19, 20, 31, 41, 42, 49, 6, 7, 17, 33, 34, 52, 8, 8, 21, 22, 23, 24, 25, 26, 27, 28, 29, 50, 51, 18, 30, 32, 47, 45, 46, 20, 0, 44 }; static const nss_expr_yysigned_char nss_expr_yycheck[] = { 21, 22, 23, 24, 25, 26, 3, 4, 5, 5, 7, 7, 23, 10, 10, 6, 7, 20, 21, 20, 21, 24, 8, 9, 45, 22, 23, 25, 19, 20, 51, 28, 28, 11, 12, 13, 14, 15, 16, 17, 18, 19, 26, 27, 0, 7, 6, 26, 25, 24, 21, -1, 28 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const unsigned char nss_expr_yystos[] = { 0, 3, 4, 5, 7, 10, 22, 23, 28, 30, 31, 32, 34, 36, 23, 31, 31, 25, 0, 20, 21, 11, 12, 13, 14, 15, 16, 17, 18, 19, 7, 24, 6, 31, 31, 34, 34, 34, 34, 34, 34, 8, 9, 35, 35, 25, 24, 26, 33, 34, 26, 27, 34 }; #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) # define YYSIZE_T __SIZE_TYPE__ #endif #if ! defined (YYSIZE_T) && defined (size_t) # define YYSIZE_T size_t #endif #if ! defined (YYSIZE_T) # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif #endif #if ! defined (YYSIZE_T) # define YYSIZE_T unsigned int #endif #define nss_expr_yyerrok (nss_expr_yyerrstatus = 0) #define nss_expr_yyclearin (nss_expr_yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto nss_expr_yyacceptlab #define YYABORT goto nss_expr_yyabortlab #define YYERROR goto nss_expr_yyerrorlab /* Like YYERROR except do call nss_expr_yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto nss_expr_yyerrlab #define YYRECOVERING() (!!nss_expr_yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (nss_expr_yychar == YYEMPTY && nss_expr_yylen == 1) \ { \ nss_expr_yychar = (Token); \ nss_expr_yylval = (Value); \ nss_expr_yytoken = YYTRANSLATE (nss_expr_yychar); \ YYPOPSTACK; \ goto nss_expr_yybackup; \ } \ else \ { \ nss_expr_yyerror ("syntax error: cannot back up");\ YYERROR; \ } \ while (0) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Compute the default location (before the actions are run). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ ((Current).first_line = (Rhs)[1].first_line, \ (Current).first_column = (Rhs)[1].first_column, \ (Current).last_line = (Rhs)[N].last_line, \ (Current).last_column = (Rhs)[N].last_column) #endif /* YYLEX -- calling `nss_expr_yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX nss_expr_yylex (YYLEX_PARAM) #else # define YYLEX nss_expr_yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (nss_expr_yydebug) \ YYFPRINTF Args; \ } while (0) # define YYDSYMPRINT(Args) \ do { \ if (nss_expr_yydebug) \ nss_expr_yysymprint Args; \ } while (0) # define YYDSYMPRINTF(Title, Token, Value, Location) \ do { \ if (nss_expr_yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ nss_expr_yysymprint (stderr, \ Token, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*------------------------------------------------------------------. | nss_expr_yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void nss_expr_yy_stack_print (short *bottom, short *top) #else static void nss_expr_yy_stack_print (bottom, top) short *bottom; short *top; #endif { YYFPRINTF (stderr, "Stack now"); for (/* Nothing. */; bottom <= top; ++bottom) YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (nss_expr_yydebug) \ nss_expr_yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void nss_expr_yy_reduce_print (int nss_expr_yyrule) #else static void nss_expr_yy_reduce_print (nss_expr_yyrule) int nss_expr_yyrule; #endif { int nss_expr_yyi; unsigned int nss_expr_yylno = nss_expr_yyrline[nss_expr_yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", nss_expr_yyrule - 1, nss_expr_yylno); /* Print the symbols being reduced, and their result. */ for (nss_expr_yyi = nss_expr_yyprhs[nss_expr_yyrule]; 0 <= nss_expr_yyrhs[nss_expr_yyi]; nss_expr_yyi++) YYFPRINTF (stderr, "%s ", nss_expr_yytname [nss_expr_yyrhs[nss_expr_yyi]]); YYFPRINTF (stderr, "-> %s\n", nss_expr_yytname [nss_expr_yyr1[nss_expr_yyrule]]); } # define YY_REDUCE_PRINT(Rule) \ do { \ if (nss_expr_yydebug) \ nss_expr_yy_reduce_print (Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int nss_expr_yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YYDSYMPRINT(Args) # define YYDSYMPRINTF(Title, Token, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #if defined (YYMAXDEPTH) && YYMAXDEPTH == 0 # undef YYMAXDEPTH #endif #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef nss_expr_yystrlen # if defined (__GLIBC__) && defined (_STRING_H) # define nss_expr_yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T # if defined (__STDC__) || defined (__cplusplus) nss_expr_yystrlen (const char *nss_expr_yystr) # else nss_expr_yystrlen (nss_expr_yystr) const char *nss_expr_yystr; # endif { register const char *nss_expr_yys = nss_expr_yystr; while (*nss_expr_yys++ != '\0') continue; return nss_expr_yys - nss_expr_yystr - 1; } # endif # endif # ifndef nss_expr_yystpcpy # if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) # define nss_expr_yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * # if defined (__STDC__) || defined (__cplusplus) nss_expr_yystpcpy (char *nss_expr_yydest, const char *nss_expr_yysrc) # else nss_expr_yystpcpy (nss_expr_yydest, nss_expr_yysrc) char *nss_expr_yydest; const char *nss_expr_yysrc; # endif { register char *nss_expr_yyd = nss_expr_yydest; register const char *nss_expr_yys = nss_expr_yysrc; while ((*nss_expr_yyd++ = *nss_expr_yys++) != '\0') continue; return nss_expr_yyd - 1; } # endif # endif #endif /* !YYERROR_VERBOSE */ #if YYDEBUG /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void nss_expr_yysymprint (FILE *nss_expr_yyoutput, int nss_expr_yytype, YYSTYPE *nss_expr_yyvaluep) #else static void nss_expr_yysymprint (nss_expr_yyoutput, nss_expr_yytype, nss_expr_yyvaluep) FILE *nss_expr_yyoutput; int nss_expr_yytype; YYSTYPE *nss_expr_yyvaluep; #endif { /* Pacify ``unused variable'' warnings. */ (void) nss_expr_yyvaluep; if (nss_expr_yytype < YYNTOKENS) { YYFPRINTF (nss_expr_yyoutput, "token %s (", nss_expr_yytname[nss_expr_yytype]); # ifdef YYPRINT YYPRINT (nss_expr_yyoutput, nss_expr_yytoknum[nss_expr_yytype], *nss_expr_yyvaluep); # endif } else YYFPRINTF (nss_expr_yyoutput, "nterm %s (", nss_expr_yytname[nss_expr_yytype]); switch (nss_expr_yytype) { default: break; } YYFPRINTF (nss_expr_yyoutput, ")"); } #endif /* ! YYDEBUG */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void nss_expr_yydestruct (int nss_expr_yytype, YYSTYPE *nss_expr_yyvaluep) #else static void nss_expr_yydestruct (nss_expr_yytype, nss_expr_yyvaluep) int nss_expr_yytype; YYSTYPE *nss_expr_yyvaluep; #endif { /* Pacify ``unused variable'' warnings. */ (void) nss_expr_yyvaluep; switch (nss_expr_yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM # if defined (__STDC__) || defined (__cplusplus) int nss_expr_yyparse (void *YYPARSE_PARAM); # else int nss_expr_yyparse (); # endif #else /* ! YYPARSE_PARAM */ #if defined (__STDC__) || defined (__cplusplus) int nss_expr_yyparse (void); #else int nss_expr_yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int nss_expr_yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE nss_expr_yylval; /* Number of syntax errors so far. */ int nss_expr_yynerrs; /*----------. | nss_expr_yyparse. | `----------*/ #ifdef YYPARSE_PARAM # if defined (__STDC__) || defined (__cplusplus) int nss_expr_yyparse (void *YYPARSE_PARAM) # else int nss_expr_yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; # endif #else /* ! YYPARSE_PARAM */ #if defined (__STDC__) || defined (__cplusplus) int nss_expr_yyparse (void) #else int nss_expr_yyparse () #endif #endif { register int nss_expr_yystate; register int nss_expr_yyn; int nss_expr_yyresult; /* Number of tokens to shift before error messages enabled. */ int nss_expr_yyerrstatus; /* Lookahead token as an internal (translated) token number. */ int nss_expr_yytoken = 0; /* Three stacks and their tools: `nss_expr_yyss': related to states, `nss_expr_yyvs': related to semantic values, `nss_expr_yyls': related to locations. Refer to the stacks thru separate pointers, to allow nss_expr_yyoverflow to reallocate them elsewhere. */ /* The state stack. */ short nss_expr_yyssa[YYINITDEPTH]; short *nss_expr_yyss = nss_expr_yyssa; register short *nss_expr_yyssp; /* The semantic value stack. */ YYSTYPE nss_expr_yyvsa[YYINITDEPTH]; YYSTYPE *nss_expr_yyvs = nss_expr_yyvsa; register YYSTYPE *nss_expr_yyvsp; #define YYPOPSTACK (nss_expr_yyvsp--, nss_expr_yyssp--) YYSIZE_T nss_expr_yystacksize = YYINITDEPTH; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE nss_expr_yyval; /* When reducing, the number of symbols on the RHS of the reduced rule. */ int nss_expr_yylen; YYDPRINTF ((stderr, "Starting parse\n")); nss_expr_yystate = 0; nss_expr_yyerrstatus = 0; nss_expr_yynerrs = 0; nss_expr_yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ nss_expr_yyssp = nss_expr_yyss; nss_expr_yyvsp = nss_expr_yyvs; goto nss_expr_yysetstate; /*------------------------------------------------------------. | nss_expr_yynewstate -- Push a new state, which is found in nss_expr_yystate. | `------------------------------------------------------------*/ nss_expr_yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. so pushing a state here evens the stacks. */ nss_expr_yyssp++; nss_expr_yysetstate: *nss_expr_yyssp = nss_expr_yystate; if (nss_expr_yyss + nss_expr_yystacksize - 1 <= nss_expr_yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T nss_expr_yysize = nss_expr_yyssp - nss_expr_yyss + 1; #ifdef nss_expr_yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *nss_expr_yyvs1 = nss_expr_yyvs; short *nss_expr_yyss1 = nss_expr_yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if nss_expr_yyoverflow is a macro. */ nss_expr_yyoverflow ("parser stack overflow", &nss_expr_yyss1, nss_expr_yysize * sizeof (*nss_expr_yyssp), &nss_expr_yyvs1, nss_expr_yysize * sizeof (*nss_expr_yyvsp), &nss_expr_yystacksize); nss_expr_yyss = nss_expr_yyss1; nss_expr_yyvs = nss_expr_yyvs1; } #else /* no nss_expr_yyoverflow */ # ifndef YYSTACK_RELOCATE goto nss_expr_yyoverflowlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= nss_expr_yystacksize) goto nss_expr_yyoverflowlab; nss_expr_yystacksize *= 2; if (YYMAXDEPTH < nss_expr_yystacksize) nss_expr_yystacksize = YYMAXDEPTH; { short *nss_expr_yyss1 = nss_expr_yyss; union nss_expr_yyalloc *nss_expr_yyptr = (union nss_expr_yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (nss_expr_yystacksize)); if (! nss_expr_yyptr) goto nss_expr_yyoverflowlab; YYSTACK_RELOCATE (nss_expr_yyss); YYSTACK_RELOCATE (nss_expr_yyvs); # undef YYSTACK_RELOCATE if (nss_expr_yyss1 != nss_expr_yyssa) YYSTACK_FREE (nss_expr_yyss1); } # endif #endif /* no nss_expr_yyoverflow */ nss_expr_yyssp = nss_expr_yyss + nss_expr_yysize - 1; nss_expr_yyvsp = nss_expr_yyvs + nss_expr_yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) nss_expr_yystacksize)); if (nss_expr_yyss + nss_expr_yystacksize - 1 <= nss_expr_yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", nss_expr_yystate)); goto nss_expr_yybackup; /*-----------. | nss_expr_yybackup. | `-----------*/ nss_expr_yybackup: /* Do appropriate processing given the current state. */ /* Read a lookahead token if we need one and don't already have one. */ /* nss_expr_yyresume: */ /* First try to decide what to do without reference to lookahead token. */ nss_expr_yyn = nss_expr_yypact[nss_expr_yystate]; if (nss_expr_yyn == YYPACT_NINF) goto nss_expr_yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (nss_expr_yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); nss_expr_yychar = YYLEX; } if (nss_expr_yychar <= YYEOF) { nss_expr_yychar = nss_expr_yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { nss_expr_yytoken = YYTRANSLATE (nss_expr_yychar); YYDSYMPRINTF ("Next token is", nss_expr_yytoken, &nss_expr_yylval, &nss_expr_yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ nss_expr_yyn += nss_expr_yytoken; if (nss_expr_yyn < 0 || YYLAST < nss_expr_yyn || nss_expr_yycheck[nss_expr_yyn] != nss_expr_yytoken) goto nss_expr_yydefault; nss_expr_yyn = nss_expr_yytable[nss_expr_yyn]; if (nss_expr_yyn <= 0) { if (nss_expr_yyn == 0 || nss_expr_yyn == YYTABLE_NINF) goto nss_expr_yyerrlab; nss_expr_yyn = -nss_expr_yyn; goto nss_expr_yyreduce; } if (nss_expr_yyn == YYFINAL) YYACCEPT; /* Shift the lookahead token. */ YYDPRINTF ((stderr, "Shifting token %s, ", nss_expr_yytname[nss_expr_yytoken])); /* Discard the token being shifted unless it is eof. */ if (nss_expr_yychar != YYEOF) nss_expr_yychar = YYEMPTY; *++nss_expr_yyvsp = nss_expr_yylval; /* Count tokens shifted since error; after three, turn off error status. */ if (nss_expr_yyerrstatus) nss_expr_yyerrstatus--; nss_expr_yystate = nss_expr_yyn; goto nss_expr_yynewstate; /*-----------------------------------------------------------. | nss_expr_yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ nss_expr_yydefault: nss_expr_yyn = nss_expr_yydefact[nss_expr_yystate]; if (nss_expr_yyn == 0) goto nss_expr_yyerrlab; goto nss_expr_yyreduce; /*-----------------------------. | nss_expr_yyreduce -- Do a reduction. | `-----------------------------*/ nss_expr_yyreduce: /* nss_expr_yyn is the number of a rule to reduce with. */ nss_expr_yylen = nss_expr_yyr2[nss_expr_yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ nss_expr_yyval = nss_expr_yyvsp[1-nss_expr_yylen]; YY_REDUCE_PRINT (nss_expr_yyn); switch (nss_expr_yyn) { case 2: #line 69 "nss_expr_parse.y" { nss_expr_info.expr = nss_expr_yyvsp[0].exVal; } break; case 3: #line 72 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_True, NULL, NULL); } break; case 4: #line 73 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_False, NULL, NULL); } break; case 5: #line 74 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_Not, nss_expr_yyvsp[0].exVal, NULL); } break; case 6: #line 75 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_Or, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 7: #line 76 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_And, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 8: #line 77 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_Comp, nss_expr_yyvsp[0].exVal, NULL); } break; case 9: #line 78 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_yyvsp[-1].exVal; } break; case 10: #line 81 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_EQ, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 11: #line 82 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_NE, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 12: #line 83 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_LT, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 13: #line 84 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_LE, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 14: #line 85 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_GT, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 15: #line 86 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_GE, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 16: #line 87 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_IN, nss_expr_yyvsp[-4].exVal, nss_expr_yyvsp[-1].exVal); } break; case 17: #line 88 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_REG, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 18: #line 89 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_NRE, nss_expr_yyvsp[-2].exVal, nss_expr_yyvsp[0].exVal); } break; case 19: #line 92 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_ListElement, nss_expr_yyvsp[0].exVal, NULL); } break; case 20: #line 93 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_ListElement, nss_expr_yyvsp[0].exVal, nss_expr_yyvsp[-2].exVal); } break; case 21: #line 96 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_Digit, nss_expr_yyvsp[0].cpVal, NULL); } break; case 22: #line 97 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_String, nss_expr_yyvsp[0].cpVal, NULL); } break; case 23: #line 98 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_make(op_Var, nss_expr_yyvsp[-1].cpVal, NULL); } break; case 24: #line 99 "nss_expr_parse.y" { nss_expr_yyval.exVal = nss_expr_yyvsp[0].exVal; } break; case 25: #line 102 "nss_expr_parse.y" { ap_regex_t *regex; if ((regex = ap_pregcomp(nss_expr_info.pool, nss_expr_yyvsp[0].cpVal, AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) { nss_expr_error = "Failed to compile regular expression"; YYERROR; } nss_expr_yyval.exVal = nss_expr_make(op_Regex, regex, NULL); } break; case 26: #line 111 "nss_expr_parse.y" { ap_regex_t *regex; if ((regex = ap_pregcomp(nss_expr_info.pool, nss_expr_yyvsp[0].cpVal, AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) { nss_expr_error = "Failed to compile regular expression"; YYERROR; } nss_expr_yyval.exVal = nss_expr_make(op_Regex, regex, NULL); } break; case 27: #line 122 "nss_expr_parse.y" { nss_expr *args = nss_expr_make(op_ListElement, nss_expr_yyvsp[-1].cpVal, NULL); nss_expr_yyval.exVal = nss_expr_make(op_Func, "file", args); } break; } /* Line 1000 of yacc.c. */ #line 1207 "y.tab.c" nss_expr_yyvsp -= nss_expr_yylen; nss_expr_yyssp -= nss_expr_yylen; YY_STACK_PRINT (nss_expr_yyss, nss_expr_yyssp); *++nss_expr_yyvsp = nss_expr_yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ nss_expr_yyn = nss_expr_yyr1[nss_expr_yyn]; nss_expr_yystate = nss_expr_yypgoto[nss_expr_yyn - YYNTOKENS] + *nss_expr_yyssp; if (0 <= nss_expr_yystate && nss_expr_yystate <= YYLAST && nss_expr_yycheck[nss_expr_yystate] == *nss_expr_yyssp) nss_expr_yystate = nss_expr_yytable[nss_expr_yystate]; else nss_expr_yystate = nss_expr_yydefgoto[nss_expr_yyn - YYNTOKENS]; goto nss_expr_yynewstate; /*------------------------------------. | nss_expr_yyerrlab -- here on detecting error | `------------------------------------*/ nss_expr_yyerrlab: /* If not already recovering from an error, report this error. */ if (!nss_expr_yyerrstatus) { ++nss_expr_yynerrs; #if YYERROR_VERBOSE nss_expr_yyn = nss_expr_yypact[nss_expr_yystate]; if (YYPACT_NINF < nss_expr_yyn && nss_expr_yyn < YYLAST) { YYSIZE_T nss_expr_yysize = 0; int nss_expr_yytype = YYTRANSLATE (nss_expr_yychar); const char* nss_expr_yyprefix; char *nss_expr_yymsg; int nss_expr_yyx; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int nss_expr_yyxbegin = nss_expr_yyn < 0 ? -nss_expr_yyn : 0; /* Stay within bounds of both nss_expr_yycheck and nss_expr_yytname. */ int nss_expr_yychecklim = YYLAST - nss_expr_yyn; int nss_expr_yyxend = nss_expr_yychecklim < YYNTOKENS ? nss_expr_yychecklim : YYNTOKENS; int nss_expr_yycount = 0; nss_expr_yyprefix = ", expecting "; for (nss_expr_yyx = nss_expr_yyxbegin; nss_expr_yyx < nss_expr_yyxend; ++nss_expr_yyx) if (nss_expr_yycheck[nss_expr_yyx + nss_expr_yyn] == nss_expr_yyx && nss_expr_yyx != YYTERROR) { nss_expr_yysize += nss_expr_yystrlen (nss_expr_yyprefix) + nss_expr_yystrlen (nss_expr_yytname [nss_expr_yyx]); nss_expr_yycount += 1; if (nss_expr_yycount == 5) { nss_expr_yysize = 0; break; } } nss_expr_yysize += (sizeof ("syntax error, unexpected ") + nss_expr_yystrlen (nss_expr_yytname[nss_expr_yytype])); nss_expr_yymsg = (char *) YYSTACK_ALLOC (nss_expr_yysize); if (nss_expr_yymsg != 0) { char *nss_expr_yyp = nss_expr_yystpcpy (nss_expr_yymsg, "syntax error, unexpected "); nss_expr_yyp = nss_expr_yystpcpy (nss_expr_yyp, nss_expr_yytname[nss_expr_yytype]); if (nss_expr_yycount < 5) { nss_expr_yyprefix = ", expecting "; for (nss_expr_yyx = nss_expr_yyxbegin; nss_expr_yyx < nss_expr_yyxend; ++nss_expr_yyx) if (nss_expr_yycheck[nss_expr_yyx + nss_expr_yyn] == nss_expr_yyx && nss_expr_yyx != YYTERROR) { nss_expr_yyp = nss_expr_yystpcpy (nss_expr_yyp, nss_expr_yyprefix); nss_expr_yyp = nss_expr_yystpcpy (nss_expr_yyp, nss_expr_yytname[nss_expr_yyx]); nss_expr_yyprefix = " or "; } } nss_expr_yyerror (nss_expr_yymsg); YYSTACK_FREE (nss_expr_yymsg); } else nss_expr_yyerror ("syntax error; also virtual memory exhausted"); } else #endif /* YYERROR_VERBOSE */ nss_expr_yyerror ("syntax error"); } if (nss_expr_yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (nss_expr_yychar <= YYEOF) { /* If at end of input, pop the error token, then the rest of the stack, then return failure. */ if (nss_expr_yychar == YYEOF) for (;;) { YYPOPSTACK; if (nss_expr_yyssp == nss_expr_yyss) YYABORT; YYDSYMPRINTF ("Error: popping", nss_expr_yystos[*nss_expr_yyssp], nss_expr_yyvsp, nss_expr_yylsp); nss_expr_yydestruct (nss_expr_yystos[*nss_expr_yyssp], nss_expr_yyvsp); } } else { YYDSYMPRINTF ("Error: discarding", nss_expr_yytoken, &nss_expr_yylval, &nss_expr_yylloc); nss_expr_yydestruct (nss_expr_yytoken, &nss_expr_yylval); nss_expr_yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto nss_expr_yyerrlab1; /*---------------------------------------------------. | nss_expr_yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ nss_expr_yyerrorlab: #ifdef __GNUC__ /* Pacify GCC when the user code never invokes YYERROR and the label nss_expr_yyerrorlab therefore never appears in user code. */ if (0) goto nss_expr_yyerrorlab; #endif nss_expr_yyvsp -= nss_expr_yylen; nss_expr_yyssp -= nss_expr_yylen; nss_expr_yystate = *nss_expr_yyssp; goto nss_expr_yyerrlab1; /*-------------------------------------------------------------. | nss_expr_yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ nss_expr_yyerrlab1: nss_expr_yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { nss_expr_yyn = nss_expr_yypact[nss_expr_yystate]; if (nss_expr_yyn != YYPACT_NINF) { nss_expr_yyn += YYTERROR; if (0 <= nss_expr_yyn && nss_expr_yyn <= YYLAST && nss_expr_yycheck[nss_expr_yyn] == YYTERROR) { nss_expr_yyn = nss_expr_yytable[nss_expr_yyn]; if (0 < nss_expr_yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (nss_expr_yyssp == nss_expr_yyss) YYABORT; YYDSYMPRINTF ("Error: popping", nss_expr_yystos[*nss_expr_yyssp], nss_expr_yyvsp, nss_expr_yylsp); nss_expr_yydestruct (nss_expr_yystos[nss_expr_yystate], nss_expr_yyvsp); YYPOPSTACK; nss_expr_yystate = *nss_expr_yyssp; YY_STACK_PRINT (nss_expr_yyss, nss_expr_yyssp); } if (nss_expr_yyn == YYFINAL) YYACCEPT; YYDPRINTF ((stderr, "Shifting error token, ")); *++nss_expr_yyvsp = nss_expr_yylval; nss_expr_yystate = nss_expr_yyn; goto nss_expr_yynewstate; /*-------------------------------------. | nss_expr_yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ nss_expr_yyacceptlab: nss_expr_yyresult = 0; goto nss_expr_yyreturn; /*-----------------------------------. | nss_expr_yyabortlab -- YYABORT comes here. | `-----------------------------------*/ nss_expr_yyabortlab: nss_expr_yyresult = 1; goto nss_expr_yyreturn; #ifndef nss_expr_yyoverflow /*----------------------------------------------. | nss_expr_yyoverflowlab -- parser overflow comes here. | `----------------------------------------------*/ nss_expr_yyoverflowlab: nss_expr_yyerror ("parser stack overflow"); nss_expr_yyresult = 2; /* Fall through. */ #endif nss_expr_yyreturn: #ifndef nss_expr_yyoverflow if (nss_expr_yyss != nss_expr_yyssa) YYSTACK_FREE (nss_expr_yyss); #endif return nss_expr_yyresult; } #line 128 "nss_expr_parse.y" int nss_expr_yyerror(char *s) { nss_expr_error = s; return 2; } mod_nss-1.0.12/nss_expr_parse.h000066400000000000000000000047601260357105600164550ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 1.875c. */ /* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum nss_expr_yytokentype { T_TRUE = 258, T_FALSE = 259, T_DIGIT = 260, T_ID = 261, T_STRING = 262, T_REGEX = 263, T_REGEX_I = 264, T_FUNC_FILE = 265, T_OP_EQ = 266, T_OP_NE = 267, T_OP_LT = 268, T_OP_LE = 269, T_OP_GT = 270, T_OP_GE = 271, T_OP_REG = 272, T_OP_NRE = 273, T_OP_IN = 274, T_OP_OR = 275, T_OP_AND = 276, T_OP_NOT = 277 }; #endif #define T_TRUE 258 #define T_FALSE 259 #define T_DIGIT 260 #define T_ID 261 #define T_STRING 262 #define T_REGEX 263 #define T_REGEX_I 264 #define T_FUNC_FILE 265 #define T_OP_EQ 266 #define T_OP_NE 267 #define T_OP_LT 268 #define T_OP_LE 269 #define T_OP_GT 270 #define T_OP_GE 271 #define T_OP_REG 272 #define T_OP_NRE 273 #define T_OP_IN 274 #define T_OP_OR 275 #define T_OP_AND 276 #define T_OP_NOT 277 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) #line 26 "nss_expr_parse.y" typedef union YYSTYPE { char *cpVal; nss_expr *exVal; } YYSTYPE; /* Line 1275 of yacc.c. */ #line 86 "y.tab.h" # define nss_expr_yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE nss_expr_yylval; mod_nss-1.0.12/nss_expr_parse.y000066400000000000000000000106051260357105600164710ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* _________________________________________________________________ ** ** Expression Parser ** _________________________________________________________________ */ %{ #include "mod_nss.h" %} %union { char *cpVal; nss_expr *exVal; } %token T_TRUE %token T_FALSE %token T_DIGIT %token T_ID %token T_STRING %token T_REGEX %token T_REGEX_I %token T_FUNC_FILE %token T_OP_EQ %token T_OP_NE %token T_OP_LT %token T_OP_LE %token T_OP_GT %token T_OP_GE %token T_OP_REG %token T_OP_NRE %token T_OP_IN %token T_OP_OR %token T_OP_AND %token T_OP_NOT %left T_OP_OR %left T_OP_AND %left T_OP_NOT %type expr %type comparison %type funccall %type regex %type words %type word %% root : expr { nss_expr_info.expr = $1; } ; expr : T_TRUE { $$ = nss_expr_make(op_True, NULL, NULL); } | T_FALSE { $$ = nss_expr_make(op_False, NULL, NULL); } | T_OP_NOT expr { $$ = nss_expr_make(op_Not, $2, NULL); } | expr T_OP_OR expr { $$ = nss_expr_make(op_Or, $1, $3); } | expr T_OP_AND expr { $$ = nss_expr_make(op_And, $1, $3); } | comparison { $$ = nss_expr_make(op_Comp, $1, NULL); } | '(' expr ')' { $$ = $2; } ; comparison: word T_OP_EQ word { $$ = nss_expr_make(op_EQ, $1, $3); } | word T_OP_NE word { $$ = nss_expr_make(op_NE, $1, $3); } | word T_OP_LT word { $$ = nss_expr_make(op_LT, $1, $3); } | word T_OP_LE word { $$ = nss_expr_make(op_LE, $1, $3); } | word T_OP_GT word { $$ = nss_expr_make(op_GT, $1, $3); } | word T_OP_GE word { $$ = nss_expr_make(op_GE, $1, $3); } | word T_OP_IN '{' words '}' { $$ = nss_expr_make(op_IN, $1, $4); } | word T_OP_REG regex { $$ = nss_expr_make(op_REG, $1, $3); } | word T_OP_NRE regex { $$ = nss_expr_make(op_NRE, $1, $3); } ; words : word { $$ = nss_expr_make(op_ListElement, $1, NULL); } | words ',' word { $$ = nss_expr_make(op_ListElement, $3, $1); } ; word : T_DIGIT { $$ = nss_expr_make(op_Digit, $1, NULL); } | T_STRING { $$ = nss_expr_make(op_String, $1, NULL); } | '%' '{' T_ID '}' { $$ = nss_expr_make(op_Var, $3, NULL); } | funccall { $$ = $1; } ; regex : T_REGEX { ap_regex_t *regex; if ((regex = ap_pregcomp(nss_expr_info.pool, $1, AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) { nss_expr_error = "Failed to compile regular expression"; YYERROR; } $$ = nss_expr_make(op_Regex, regex, NULL); } | T_REGEX_I { ap_regex_t *regex; if ((regex = ap_pregcomp(nss_expr_info.pool, $1, AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) { nss_expr_error = "Failed to compile regular expression"; YYERROR; } $$ = nss_expr_make(op_Regex, regex, NULL); } ; funccall : T_FUNC_FILE '(' T_STRING ')' { nss_expr *args = nss_expr_make(op_ListElement, $3, NULL); $$ = nss_expr_make(op_Func, "file", args); } ; %% int yyerror(char *s) { nss_expr_error = s; return 2; } mod_nss-1.0.12/nss_expr_scan.c000066400000000000000000001332421260357105600162600ustar00rootroot00000000000000#define yy_create_buffer nss_expr_yy_create_buffer #define yy_delete_buffer nss_expr_yy_delete_buffer #define yy_scan_buffer nss_expr_yy_scan_buffer #define yy_scan_string nss_expr_yy_scan_string #define yy_scan_bytes nss_expr_yy_scan_bytes #define yy_flex_debug nss_expr_yy_flex_debug #define yy_init_buffer nss_expr_yy_init_buffer #define yy_flush_buffer nss_expr_yy_flush_buffer #define yy_load_buffer_state nss_expr_yy_load_buffer_state #define yy_switch_to_buffer nss_expr_yy_switch_to_buffer #define yyin nss_expr_yyin #define yyleng nss_expr_yyleng #define yylex nss_expr_yylex #define yyout nss_expr_yyout #define yyrestart nss_expr_yyrestart #define yytext nss_expr_yytext /* A lexical scanner generated by flex */ /* Scanner skeleton version: */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #include #include /* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ #ifdef c_plusplus #ifndef __cplusplus #define __cplusplus #endif #endif #ifdef __cplusplus #include /* Use prototypes in function declarations. */ #define YY_USE_PROTOS /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define YY_USE_PROTOS #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef __TURBOC__ #pragma warn -rch #pragma warn -use #include #include #define YY_USE_CONST #define YY_USE_PROTOS #endif #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif #ifdef YY_USE_PROTOS #define YY_PROTO(proto) proto #else #define YY_PROTO(proto) () #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #define YY_BUF_SIZE 16384 typedef struct yy_buffer_state *YY_BUFFER_STATE; extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* The funky do-while in the following #define is used to turn the definition * int a single C statement (which needs a semi-colon terminator). This * avoids problems with code like: * * if ( condition_holds ) * yyless( 5 ); * else * do_something_else(); * * Prior to using the do-while the compiler would get upset at the * "else" because it interpreted the "if" statement as being all * done when it reached the ';' after the yyless() call. */ /* Return all but the first 'n' matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ *yy_cp = yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yytext_ptr ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ typedef unsigned int yy_size_t; struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; static YY_BUFFER_STATE yy_current_buffer = 0; /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". */ #define YY_CURRENT_BUFFER yy_current_buffer /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 1; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart YY_PROTO(( FILE *input_file )); void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); void yy_load_buffer_state YY_PROTO(( void )); YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); #define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); static void *yy_flex_alloc YY_PROTO(( yy_size_t )); static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); static void yy_flex_free YY_PROTO(( void * )); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (yy_current_buffer->yy_at_bol) #define yywrap() 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state YY_PROTO(( void )); static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); static int yy_get_next_buffer YY_PROTO(( void )); static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yytext_ptr = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yy_c_buf_p = yy_cp; #define YY_NUM_RULES 46 #define YY_END_OF_BUFFER 47 static yyconst short int yy_accept[86] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 45, 1, 38, 2, 45, 43, 24, 45, 28, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 13, 4, 3, 14, 16, 18, 17, 1, 22, 32, 34, 43, 26, 20, 31, 30, 44, 44, 19, 44, 44, 29, 27, 39, 25, 23, 15, 15, 21, 44, 35, 44, 36, 13, 12, 5, 6, 10, 11, 7, 8, 9, 33, 44, 44, 37, 44, 5, 6, 44, 40, 41, 5, 42, 0 } ; static yyconst int yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 5, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 7, 1, 1, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 7, 1, 10, 11, 12, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 14, 1, 1, 7, 1, 15, 16, 13, 17, 18, 19, 20, 13, 21, 13, 13, 22, 23, 24, 25, 13, 26, 27, 28, 29, 30, 13, 13, 13, 13, 13, 1, 31, 1, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst int yy_meta[33] = { 0, 1, 1, 2, 1, 3, 1, 4, 4, 4, 1, 1, 1, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1 } ; static yyconst short int yy_base[93] = { 0, 0, 0, 30, 31, 0, 0, 82, 81, 101, 142, 35, 28, 142, 94, 32, 88, 31, 87, 0, 69, 66, 28, 28, 67, 29, 63, 30, 63, 62, 57, 0, 142, 142, 88, 142, 142, 142, 48, 142, 142, 142, 44, 142, 142, 142, 142, 0, 70, 0, 64, 63, 0, 0, 0, 0, 0, 142, 0, 0, 55, 0, 46, 142, 0, 142, 53, 62, 142, 142, 142, 142, 142, 0, 44, 48, 0, 41, 70, 72, 38, 0, 0, 74, 0, 142, 117, 121, 125, 50, 129, 133, 137 } ; static yyconst short int yy_def[93] = { 0, 85, 1, 86, 86, 87, 87, 88, 88, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 89, 89, 89, 89, 89, 89, 89, 90, 89, 89, 89, 85, 91, 85, 85, 92, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 85, 89, 89, 89, 89, 89, 85, 91, 85, 85, 85, 85, 85, 85, 85, 85, 89, 89, 89, 89, 89, 85, 85, 89, 89, 89, 85, 89, 0, 85, 85, 85, 85, 85, 85, 85 } ; static yyconst short int yy_nxt[175] = { 0, 10, 11, 11, 12, 13, 14, 10, 15, 15, 16, 17, 18, 19, 10, 20, 19, 19, 21, 22, 23, 24, 25, 26, 27, 28, 19, 19, 19, 29, 19, 30, 10, 32, 32, 33, 33, 38, 38, 39, 42, 42, 44, 50, 34, 34, 52, 55, 59, 51, 38, 38, 42, 42, 47, 60, 84, 53, 56, 82, 40, 78, 79, 45, 57, 57, 81, 57, 57, 57, 79, 79, 80, 57, 57, 57, 77, 57, 83, 79, 79, 79, 79, 79, 76, 75, 74, 73, 63, 62, 61, 54, 49, 48, 57, 57, 66, 67, 46, 43, 41, 85, 37, 37, 68, 85, 85, 69, 85, 85, 85, 85, 70, 85, 85, 71, 85, 72, 31, 31, 31, 31, 35, 35, 35, 35, 36, 36, 36, 36, 58, 85, 58, 58, 64, 85, 85, 64, 65, 65, 65, 65, 9, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 } ; static yyconst short int yy_chk[175] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 3, 4, 11, 11, 12, 15, 15, 17, 22, 3, 4, 23, 25, 27, 22, 38, 38, 42, 42, 89, 27, 80, 23, 25, 77, 12, 66, 66, 17, 26, 26, 75, 26, 26, 26, 67, 67, 74, 26, 26, 26, 62, 26, 78, 78, 79, 79, 83, 83, 60, 51, 50, 48, 30, 29, 28, 24, 21, 20, 26, 26, 34, 34, 18, 16, 14, 9, 8, 7, 34, 0, 0, 34, 0, 0, 0, 0, 34, 0, 0, 34, 0, 34, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 90, 0, 90, 90, 91, 0, 0, 91, 92, 92, 92, 92, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "nss_expr_scan.l" #define INITIAL 0 /* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* _________________________________________________________________ ** ** Expression Scanner ** _________________________________________________________________ */ #line 23 "nss_expr_scan.l" #include "mod_nss.h" #include "nss_expr_parse.h" #define YY_NO_UNPUT 1 int yyinput(char *buf, int max_size); #undef YY_INPUT #define YY_INPUT(buf,result,max_size) \ (result = yyinput(buf, max_size)) #define MAX_STR_LEN 2048 /* %option stack */ #define YY_NEVER_INTERACTIVE 1 #define str 1 #define regex 2 #define regex_flags 3 #line 489 "lex.nss_expr_yy.c" /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap YY_PROTO(( void )); #else extern int yywrap YY_PROTO(( void )); #endif #endif #ifndef YY_NO_UNPUT static void yyunput YY_PROTO(( int c, char *buf_ptr )); #endif #ifndef yytext_ptr static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen YY_PROTO(( yyconst char * )); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput YY_PROTO(( void )); #else static int input YY_PROTO(( void )); #endif #endif #if YY_STACK_USED static int yy_start_stack_ptr = 0; static int yy_start_stack_depth = 0; static int *yy_start_stack = 0; #ifndef YY_NO_PUSH_STATE static void yy_push_state YY_PROTO(( int new_state )); #endif #ifndef YY_NO_POP_STATE static void yy_pop_state YY_PROTO(( void )); #endif #ifndef YY_NO_TOP_STATE static int yy_top_state YY_PROTO(( void )); #endif #else #define YY_NO_PUSH_STATE 1 #define YY_NO_POP_STATE 1 #define YY_NO_TOP_STATE 1 #endif #ifdef YY_MALLOC_DECL YY_MALLOC_DECL #else #if __STDC__ #ifndef __cplusplus #include #endif #else /* Just try to get by without declaring the routines. This will fail * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) * or sizeof(void*) != sizeof(int). */ #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( yy_current_buffer->yy_is_interactive ) \ { \ int c = '*', n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL int yylex YY_PROTO(( void )) #endif /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION YY_DECL { register yy_state_type yy_current_state; register char *yy_cp = NULL, *yy_bp = NULL; register int yy_act; #line 44 "nss_expr_scan.l" char caStr[MAX_STR_LEN]; char *cpStr = NULL; char caRegex[MAX_STR_LEN]; char *cpRegex = NULL; char cRegexDel = NUL; /* * Whitespaces */ #line 652 "lex.nss_expr_yy.c" if ( yy_init ) { yy_init = 0; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yy_start ) yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! yy_current_buffer ) yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); yy_load_buffer_state(); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = yy_c_buf_p; /* Support of yytext. */ *yy_cp = yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yy_start; yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 86 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_current_state != 85 ); yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yy_hold_char; yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP #line 55 "nss_expr_scan.l" { /* NOP */ } YY_BREAK /* * C-style strings ("...") */ case 2: YY_RULE_SETUP #line 62 "nss_expr_scan.l" { cpStr = caStr; BEGIN(str); } YY_BREAK case 3: YY_RULE_SETUP #line 66 "nss_expr_scan.l" { BEGIN(INITIAL); *cpStr = NUL; yylval.cpVal = apr_pstrdup(nss_expr_info.pool, caStr); return T_STRING; } YY_BREAK case 4: YY_RULE_SETUP #line 72 "nss_expr_scan.l" { yyerror("Unterminated string"); } YY_BREAK case 5: YY_RULE_SETUP #line 75 "nss_expr_scan.l" { int result; (void)sscanf(yytext+1, "%o", &result); if (result > 0xff) yyerror("Escape sequence out of bound"); else *cpStr++ = result; } YY_BREAK case 6: YY_RULE_SETUP #line 84 "nss_expr_scan.l" { yyerror("Bad escape sequence"); } YY_BREAK case 7: YY_RULE_SETUP #line 87 "nss_expr_scan.l" { *cpStr++ = '\n'; } YY_BREAK case 8: YY_RULE_SETUP #line 88 "nss_expr_scan.l" { *cpStr++ = '\r'; } YY_BREAK case 9: YY_RULE_SETUP #line 89 "nss_expr_scan.l" { *cpStr++ = '\t'; } YY_BREAK case 10: YY_RULE_SETUP #line 90 "nss_expr_scan.l" { *cpStr++ = '\b'; } YY_BREAK case 11: YY_RULE_SETUP #line 91 "nss_expr_scan.l" { *cpStr++ = '\f'; } YY_BREAK case 12: YY_RULE_SETUP #line 92 "nss_expr_scan.l" { *cpStr++ = yytext[1]; } YY_BREAK case 13: YY_RULE_SETUP #line 95 "nss_expr_scan.l" { char *cp = yytext; while (*cp != NUL) *cpStr++ = *cp++; } YY_BREAK case 14: YY_RULE_SETUP #line 100 "nss_expr_scan.l" { *cpStr++ = yytext[1]; } YY_BREAK /* * Regular Expression */ case 15: YY_RULE_SETUP #line 107 "nss_expr_scan.l" { cRegexDel = yytext[1]; cpRegex = caRegex; BEGIN(regex); } YY_BREAK case 16: YY_RULE_SETUP #line 112 "nss_expr_scan.l" { if (yytext[0] == cRegexDel) { *cpRegex = NUL; BEGIN(regex_flags); } else { *cpRegex++ = yytext[0]; } } YY_BREAK case 17: YY_RULE_SETUP #line 121 "nss_expr_scan.l" { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, caRegex); BEGIN(INITIAL); return T_REGEX_I; } YY_BREAK case 18: YY_RULE_SETUP #line 126 "nss_expr_scan.l" { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, caRegex); yyless(0); BEGIN(INITIAL); return T_REGEX; } YY_BREAK case YY_STATE_EOF(regex_flags): #line 132 "nss_expr_scan.l" { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, caRegex); BEGIN(INITIAL); return T_REGEX; } YY_BREAK /* * Operators */ case 19: YY_RULE_SETUP #line 141 "nss_expr_scan.l" { return T_OP_EQ; } YY_BREAK case 20: YY_RULE_SETUP #line 142 "nss_expr_scan.l" { return T_OP_EQ; } YY_BREAK case 21: YY_RULE_SETUP #line 143 "nss_expr_scan.l" { return T_OP_NE; } YY_BREAK case 22: YY_RULE_SETUP #line 144 "nss_expr_scan.l" { return T_OP_NE; } YY_BREAK case 23: YY_RULE_SETUP #line 145 "nss_expr_scan.l" { return T_OP_LT; } YY_BREAK case 24: YY_RULE_SETUP #line 146 "nss_expr_scan.l" { return T_OP_LT; } YY_BREAK case 25: YY_RULE_SETUP #line 147 "nss_expr_scan.l" { return T_OP_LE; } YY_BREAK case 26: YY_RULE_SETUP #line 148 "nss_expr_scan.l" { return T_OP_LE; } YY_BREAK case 27: YY_RULE_SETUP #line 149 "nss_expr_scan.l" { return T_OP_GT; } YY_BREAK case 28: YY_RULE_SETUP #line 150 "nss_expr_scan.l" { return T_OP_GT; } YY_BREAK case 29: YY_RULE_SETUP #line 151 "nss_expr_scan.l" { return T_OP_GE; } YY_BREAK case 30: YY_RULE_SETUP #line 152 "nss_expr_scan.l" { return T_OP_GE; } YY_BREAK case 31: YY_RULE_SETUP #line 153 "nss_expr_scan.l" { return T_OP_REG; } YY_BREAK case 32: YY_RULE_SETUP #line 154 "nss_expr_scan.l" { return T_OP_NRE; } YY_BREAK case 33: YY_RULE_SETUP #line 155 "nss_expr_scan.l" { return T_OP_AND; } YY_BREAK case 34: YY_RULE_SETUP #line 156 "nss_expr_scan.l" { return T_OP_AND; } YY_BREAK case 35: YY_RULE_SETUP #line 157 "nss_expr_scan.l" { return T_OP_OR; } YY_BREAK case 36: YY_RULE_SETUP #line 158 "nss_expr_scan.l" { return T_OP_OR; } YY_BREAK case 37: YY_RULE_SETUP #line 159 "nss_expr_scan.l" { return T_OP_NOT; } YY_BREAK case 38: YY_RULE_SETUP #line 160 "nss_expr_scan.l" { return T_OP_NOT; } YY_BREAK case 39: YY_RULE_SETUP #line 161 "nss_expr_scan.l" { return T_OP_IN; } YY_BREAK /* * Functions */ case 40: YY_RULE_SETUP #line 166 "nss_expr_scan.l" { return T_FUNC_FILE; } YY_BREAK /* * Specials */ case 41: YY_RULE_SETUP #line 171 "nss_expr_scan.l" { return T_TRUE; } YY_BREAK case 42: YY_RULE_SETUP #line 172 "nss_expr_scan.l" { return T_FALSE; } YY_BREAK /* * Digits */ case 43: YY_RULE_SETUP #line 177 "nss_expr_scan.l" { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, yytext); return T_DIGIT; } YY_BREAK /* * Identifiers */ case 44: YY_RULE_SETUP #line 185 "nss_expr_scan.l" { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, yytext); return T_ID; } YY_BREAK /* * Anything else is returned as is... */ case 45: YY_RULE_SETUP #line 193 "nss_expr_scan.l" { return yytext[0]; } YY_BREAK case 46: YY_RULE_SETUP #line 197 "nss_expr_scan.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK #line 1052 "lex.nss_expr_yy.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(str): case YY_STATE_EOF(regex): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between yy_current_buffer and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yy_n_chars = yy_current_buffer->yy_n_chars; yy_current_buffer->yy_input_file = yyin; yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; goto yy_find_action; } } else switch ( yy_get_next_buffer() ) { case EOB_ACT_END_OF_FILE: { yy_did_buffer_switch_on_eof = 0; if ( yywrap() ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(); yy_cp = yy_c_buf_p; yy_bp = yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yy_c_buf_p = &yy_current_buffer->yy_ch_buf[yy_n_chars]; yy_current_state = yy_get_previous_state(); yy_cp = yy_c_buf_p; yy_bp = yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer() { register char *dest = yy_current_buffer->yy_ch_buf; register char *source = yytext_ptr; register int number_to_move, i; int ret_val; if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( yy_current_buffer->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ yy_current_buffer->yy_n_chars = yy_n_chars = 0; else { int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ #ifdef YY_USES_REJECT YY_FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); #else /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = yy_current_buffer; int yy_c_buf_p_offset = (int) (yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yy_flex_realloc( (void *) b->yy_ch_buf, b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; #endif } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), yy_n_chars, num_to_read ); yy_current_buffer->yy_n_chars = yy_n_chars; } if ( yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; yy_current_buffer->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; yy_n_chars += number_to_move; yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state() { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = yy_start; for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 86 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ #ifdef YY_USE_PROTOS static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) #else static yy_state_type yy_try_NUL_trans( yy_current_state ) yy_state_type yy_current_state; #endif { register int yy_is_jam; register char *yy_cp = yy_c_buf_p; register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 86 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 85); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #ifdef YY_USE_PROTOS static void yyunput( int c, register char *yy_bp ) #else static void yyunput( c, yy_bp ) int c; register char *yy_bp; #endif { register char *yy_cp = yy_c_buf_p; /* undo effects of setting up yytext */ *yy_cp = yy_hold_char; if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = yy_n_chars + 2; register char *dest = &yy_current_buffer->yy_ch_buf[ yy_current_buffer->yy_buf_size + 2]; register char *source = &yy_current_buffer->yy_ch_buf[number_to_move]; while ( source > yy_current_buffer->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); yy_current_buffer->yy_n_chars = yy_n_chars = yy_current_buffer->yy_buf_size; if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; yytext_ptr = yy_bp; yy_hold_char = *yy_cp; yy_c_buf_p = yy_cp; } #endif /* ifndef YY_NO_UNPUT */ #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput() #else static int input() #endif { int c; *yy_c_buf_p = yy_hold_char; if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) /* This was really a NUL. */ *yy_c_buf_p = '\0'; else { /* need more input */ int offset = yy_c_buf_p - yytext_ptr; ++yy_c_buf_p; switch ( yy_get_next_buffer() ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin ); /* fall through */ case EOB_ACT_END_OF_FILE: { if ( yywrap() ) return EOF; if ( ! yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: yy_c_buf_p = yytext_ptr + offset; break; } } } c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ *yy_c_buf_p = '\0'; /* preserve yytext */ yy_hold_char = *++yy_c_buf_p; return c; } #endif /* YY_NO_INPUT */ #ifdef YY_USE_PROTOS void yyrestart( FILE *input_file ) #else void yyrestart( input_file ) FILE *input_file; #endif { if ( ! yy_current_buffer ) yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); yy_init_buffer( yy_current_buffer, input_file ); yy_load_buffer_state(); } #ifdef YY_USE_PROTOS void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) #else void yy_switch_to_buffer( new_buffer ) YY_BUFFER_STATE new_buffer; #endif { if ( yy_current_buffer == new_buffer ) return; if ( yy_current_buffer ) { /* Flush out information for old buffer. */ *yy_c_buf_p = yy_hold_char; yy_current_buffer->yy_buf_pos = yy_c_buf_p; yy_current_buffer->yy_n_chars = yy_n_chars; } yy_current_buffer = new_buffer; yy_load_buffer_state(); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yy_did_buffer_switch_on_eof = 1; } #ifdef YY_USE_PROTOS void yy_load_buffer_state( void ) #else void yy_load_buffer_state() #endif { yy_n_chars = yy_current_buffer->yy_n_chars; yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; yyin = yy_current_buffer->yy_input_file; yy_hold_char = *yy_c_buf_p; } #ifdef YY_USE_PROTOS YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) #else YY_BUFFER_STATE yy_create_buffer( file, size ) FILE *file; int size; #endif { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file ); return b; } #ifdef YY_USE_PROTOS void yy_delete_buffer( YY_BUFFER_STATE b ) #else void yy_delete_buffer( b ) YY_BUFFER_STATE b; #endif { if ( ! b ) return; if ( b == yy_current_buffer ) yy_current_buffer = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yy_flex_free( (void *) b->yy_ch_buf ); yy_flex_free( (void *) b ); } #ifdef YY_USE_PROTOS void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) #else void yy_init_buffer( b, file ) YY_BUFFER_STATE b; FILE *file; #endif { yy_flush_buffer( b ); b->yy_input_file = file; b->yy_fill_buffer = 1; #if YY_ALWAYS_INTERACTIVE b->yy_is_interactive = 1; #else #if YY_NEVER_INTERACTIVE b->yy_is_interactive = 0; #else b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; #endif #endif } #ifdef YY_USE_PROTOS void yy_flush_buffer( YY_BUFFER_STATE b ) #else void yy_flush_buffer( b ) YY_BUFFER_STATE b; #endif { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == yy_current_buffer ) yy_load_buffer_state(); } #ifndef YY_NO_SCAN_BUFFER #ifdef YY_USE_PROTOS YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) #else YY_BUFFER_STATE yy_scan_buffer( base, size ) char *base; yy_size_t size; #endif { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b ); return b; } #endif #ifndef YY_NO_SCAN_STRING #ifdef YY_USE_PROTOS YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) #else YY_BUFFER_STATE yy_scan_string( yy_str ) yyconst char *yy_str; #endif { int len; for ( len = 0; yy_str[len]; ++len ) ; return yy_scan_bytes( yy_str, len ); } #endif #ifndef YY_NO_SCAN_BYTES #ifdef YY_USE_PROTOS YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) #else YY_BUFFER_STATE yy_scan_bytes( bytes, len ) yyconst char *bytes; int len; #endif { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = len + 2; buf = (char *) yy_flex_alloc( n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < len; ++i ) buf[i] = bytes[i]; buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #endif #ifndef YY_NO_PUSH_STATE #ifdef YY_USE_PROTOS static void yy_push_state( int new_state ) #else static void yy_push_state( new_state ) int new_state; #endif { if ( yy_start_stack_ptr >= yy_start_stack_depth ) { yy_size_t new_size; yy_start_stack_depth += YY_START_STACK_INCR; new_size = yy_start_stack_depth * sizeof( int ); if ( ! yy_start_stack ) yy_start_stack = (int *) yy_flex_alloc( new_size ); else yy_start_stack = (int *) yy_flex_realloc( (void *) yy_start_stack, new_size ); if ( ! yy_start_stack ) YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); } yy_start_stack[yy_start_stack_ptr++] = YY_START; BEGIN(new_state); } #endif #ifndef YY_NO_POP_STATE static void yy_pop_state() { if ( --yy_start_stack_ptr < 0 ) YY_FATAL_ERROR( "start-condition stack underflow" ); BEGIN(yy_start_stack[yy_start_stack_ptr]); } #endif #ifndef YY_NO_TOP_STATE static int yy_top_state() { return yy_start_stack[yy_start_stack_ptr - 1]; } #endif #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif #ifdef YY_USE_PROTOS static void yy_fatal_error( yyconst char msg[] ) #else static void yy_fatal_error( msg ) char msg[]; #endif { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ yytext[yyleng] = yy_hold_char; \ yy_c_buf_p = yytext + n; \ yy_hold_char = *yy_c_buf_p; \ *yy_c_buf_p = '\0'; \ yyleng = n; \ } \ while ( 0 ) /* Internal utility routines. */ #ifndef yytext_ptr #ifdef YY_USE_PROTOS static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) #else static void yy_flex_strncpy( s1, s2, n ) char *s1; yyconst char *s2; int n; #endif { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN #ifdef YY_USE_PROTOS static int yy_flex_strlen( yyconst char *s ) #else static int yy_flex_strlen( s ) yyconst char *s; #endif { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif #ifdef YY_USE_PROTOS static void *yy_flex_alloc( yy_size_t size ) #else static void *yy_flex_alloc( size ) yy_size_t size; #endif { return (void *) malloc( size ); } #ifdef YY_USE_PROTOS static void *yy_flex_realloc( void *ptr, yy_size_t size ) #else static void *yy_flex_realloc( ptr, size ) void *ptr; yy_size_t size; #endif { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } #ifdef YY_USE_PROTOS static void yy_flex_free( void *ptr ) #else static void yy_flex_free( ptr ) void *ptr; #endif { free( ptr ); } #if YY_MAIN int main() { yylex(); return 0; } #endif #line 197 "nss_expr_scan.l" int yyinput(char *buf, int max_size) { int n; if ((n = MIN(max_size, nss_expr_info.inputbuf + nss_expr_info.inputlen - nss_expr_info.inputptr)) <= 0) return YY_NULL; memcpy(buf, nss_expr_info.inputptr, n); nss_expr_info.inputptr += n; return n; } mod_nss-1.0.12/nss_expr_scan.l000066400000000000000000000101011260357105600162550ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* _________________________________________________________________ ** ** Expression Scanner ** _________________________________________________________________ */ %{ #include "mod_nss.h" #include "nss_expr_parse.h" #define YY_NO_UNPUT 1 int yyinput(char *buf, int max_size); #undef YY_INPUT #define YY_INPUT(buf,result,max_size) \ (result = yyinput(buf, max_size)) #define MAX_STR_LEN 2048 %} %pointer /* %option stack */ %option never-interactive %option noyywrap %x str %x regex regex_flags %% char caStr[MAX_STR_LEN]; char *cpStr = NULL; char caRegex[MAX_STR_LEN]; char *cpRegex = NULL; char cRegexDel = NUL; /* * Whitespaces */ [ \t\n]+ { /* NOP */ } /* * C-style strings ("...") */ \" { cpStr = caStr; BEGIN(str); } \" { BEGIN(INITIAL); *cpStr = NUL; yylval.cpVal = apr_pstrdup(nss_expr_info.pool, caStr); return T_STRING; } \n { yyerror("Unterminated string"); } \\[0-7]{1,3} { int result; (void)sscanf(yytext+1, "%o", &result); if (result > 0xff) yyerror("Escape sequence out of bound"); else *cpStr++ = result; } \\[0-9]+ { yyerror("Bad escape sequence"); } \\n { *cpStr++ = '\n'; } \\r { *cpStr++ = '\r'; } \\t { *cpStr++ = '\t'; } \\b { *cpStr++ = '\b'; } \\f { *cpStr++ = '\f'; } \\(.|\n) { *cpStr++ = yytext[1]; } [^\\\n\"]+ { char *cp = yytext; while (*cp != NUL) *cpStr++ = *cp++; } . { *cpStr++ = yytext[1]; } /* * Regular Expression */ "m". { cRegexDel = yytext[1]; cpRegex = caRegex; BEGIN(regex); } .|\n { if (yytext[0] == cRegexDel) { *cpRegex = NUL; BEGIN(regex_flags); } else { *cpRegex++ = yytext[0]; } } i { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, caRegex); BEGIN(INITIAL); return T_REGEX_I; } .|\n { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, caRegex); yyless(0); BEGIN(INITIAL); return T_REGEX; } <> { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, caRegex); BEGIN(INITIAL); return T_REGEX; } /* * Operators */ "eq" { return T_OP_EQ; } "==" { return T_OP_EQ; } "ne" { return T_OP_NE; } "!=" { return T_OP_NE; } "lt" { return T_OP_LT; } "<" { return T_OP_LT; } "le" { return T_OP_LE; } "<=" { return T_OP_LE; } "gt" { return T_OP_GT; } ">" { return T_OP_GT; } "ge" { return T_OP_GE; } ">=" { return T_OP_GE; } "=~" { return T_OP_REG; } "!~" { return T_OP_NRE; } "and" { return T_OP_AND; } "&&" { return T_OP_AND; } "or" { return T_OP_OR; } "||" { return T_OP_OR; } "not" { return T_OP_NOT; } "!" { return T_OP_NOT; } "in" { return T_OP_IN; } /* * Functions */ "file" { return T_FUNC_FILE; } /* * Specials */ "true" { return T_TRUE; } "false" { return T_FALSE; } /* * Digits */ [0-9]+ { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, yytext); return T_DIGIT; } /* * Identifiers */ [a-zA-Z][a-zA-Z0-9_:-]* { yylval.cpVal = apr_pstrdup(nss_expr_info.pool, yytext); return T_ID; } /* * Anything else is returned as is... */ .|\n { return yytext[0]; } %% int yyinput(char *buf, int max_size) { int n; if ((n = MIN(max_size, nss_expr_info.inputbuf + nss_expr_info.inputlen - nss_expr_info.inputptr)) <= 0) return YY_NULL; memcpy(buf, nss_expr_info.inputptr, n); nss_expr_info.inputptr += n; return n; } mod_nss-1.0.12/nss_pcache.8000066400000000000000000000073701260357105600154500ustar00rootroot00000000000000.\" A man page for nss_pcache .\" .\" Licensed under the Apache License, Version 2.0 (the "License"); .\" you may not use this file except in compliance with the License. .\" You may obtain a copy of the License at .\" .\" http://www.apache.org/licenses/LICENSE-2.0 .\" .\" Unless required by applicable law or agreed to in writing, software .\" distributed under the License is distributed on an "AS IS" BASIS, .\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" See the License for the specific language governing permissions and .\" limitations under the License. .\" .\" Author: Rob Crittenden .\" .TH "nss_pcache" "8" "Jul 1 2013" "Rob Crittenden" "" .SH "NAME" nss_pcache \- Helper program used to store token password pins .SH "SYNOPSIS" nss_pcache [prefix] .SH "DESCRIPTION" A helper program used by the Apache \fBhttpd\fP mod_nss plug-in to store the NSS PKCS #11 token password pins between restarts of Apache. .PP Whenever an Apache \fBhttpd\fP process configured to use the mod_nss plug-in is started, this program will be automatically invoked via reference to the mod_nss configuration file stored under \fB/etc/httpd/conf.d/nss.conf\fP which contains the following default entry: .IP # Pass Phrase Helper: .br # This helper program stores the token password pins between .br # restarts of Apache. .br # .br # NOTE: Located at '/usr/sbin/nss_pcache' prior .br # to 'mod_nss-1.0.8-22'. .br # .br NSSPassPhraseHelper /usr/libexec/nss_pcache .SH OPTIONS .TP .B The semaphore which corresponds to the mod_nss plug-in registered with the Apache \fBhttpd\fP process during startup. .TP .B Specifies whether FIPS mode should be enabled, \fBon\fP, or disabled, \fBoff\fP. By default, FIPS mode is disabled, and no variable is specified in \fB/etc/httpd/conf.d/nss.conf\fP. To enable FIPS mode, establish password access for the specified NSS security databases, and specify the following variable in \fB/etc/httpd/conf.d/nss.conf\fP: .IP .TS tab(;); ll,ll. ;NSSFIPS on .TE .TP .B Specifies the destination directory of the NSS databases that will be associated with this executable specified by the following entry in \fB/etc/httpd/conf.d/nss.conf\fP: .IP .TS tab(;); ll,ll. ;# Server Certificate Database: ;# The NSS security database directory that holds the ;# certificates and keys. The database consists ;# of 3 files: cert8.db, key3.db and secmod.db. ;# Provide the directory that these files exist. ;NSSCertificateDatabase /etc/httpd/alias .TE .TP .B [prefix] Optional prefix to attach prior to the names of the NSS certificate and key databases contained in the directory referenced by the previous argument and specified by the following entry in \fB/etc/httpd/conf.d/nss.conf\fP (must be uncommented in order to be utilized): .IP .TS tab(;); ll,ll. ;# Database Prefix: ;# In order to be able to store multiple NSS databases ;# in one directory they need unique names. This option ;# sets the database prefix used for cert8.db and key3.db. ;#NSSDBPrefix my-prefix- .TE .SH BUGS Report bugs to http://bugzilla.redhat.com. .SH AUTHORS Rob Crittenden . .SH COPYRIGHT Copyright (c) 2013 Red Hat, Inc. This is licensed under the Apache License, Version 2.0 (the "License"); no one may use this file except in compliance with the License. A copy of this license is available at http://www.apache.org/licenses/LICENSE-2.0. .PP Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mod_nss-1.0.12/nss_pcache.c000066400000000000000000000330511260357105600155160ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "nss_pcache.h" static char * getstr(const char * cmd, int el); char* INTERNAL_TOKEN_NAME = "internal "; /* * Mechanisms for doing the PIN encryption. Each of these lists * an encryption mechanism, with setup, encode and decode routines that * use that mechanism. The PK11PinStore looks for a mechanism * that the token supports, and then uses it. If none is found, * it will fail. */ typedef struct mech_item mech_item; struct mech_item { CK_MECHANISM_TYPE type; const char *mechName; }; /* * The table listing all mechanism to try */ #define MECH_TABLE_SIZE 4 static const mech_item table[MECH_TABLE_SIZE] = { { CKM_SKIPJACK_CBC64, "Skipjack CBC-64 encryption" }, { CKM_DES3_CBC, "Triple-DES CBC encryption" }, { CKM_CAST128_CBC, "CAST-128 CBC encryption" }, { CKM_DES_CBC, "DES CBC encryption" } }; static mech_item dflt_mech = { CKM_DES3_CBC, "Triple-DES CBC (default)" }; /* * Implementation */ struct Pk11PinStore { PK11SlotInfo *slot; const mech_item *mech; PK11SymKey *key; SECItem *params; int length; unsigned char *crypt; }; union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; /* * Node - for maintaining link list of tokens with cached PINs */ typedef struct Node Node; static void freeList(Node *list); struct Node { Node *next; char *tokenName; Pk11PinStore *store; }; /* global variables */ Node *pinList = NULL; /* * CreatePk11PinStore */ int CreatePk11PinStore(Pk11PinStore **out, const char *tokenName, const char *pin) { int err = PIN_SUCCESS; Pk11PinStore *store; do { store = (Pk11PinStore*)malloc(sizeof(Pk11PinStore)); if (store == 0) { err = PIN_NOMEMORY; break; } /* Low-level init */ store->key = 0; store->params = 0; store->crypt = 0; /* Use the tokenName to find a PKCS11 slot */ store->slot = PK11_FindSlotByName((char *)tokenName); if (store->slot == 0) { err = PIN_NOSUCHTOKEN; break; } /* Check the password/PIN. This allows access to the token */ { SECStatus rv = PK11_CheckUserPassword(store->slot, (char *)pin); if (rv == SECSuccess) ; else if (rv == SECWouldBlock) { /* NSS returns a blocking error when the pin is wrong */ err = PIN_INCORRECTPW; break; } else { err = PIN_SYSTEMERROR; break; } } /* Find the mechanism that this token can do */ { const mech_item *tp; store->mech = 0; for(tp = table;tp < &table[MECH_TABLE_SIZE];tp++) { if (PK11_DoesMechanism(store->slot, tp->type)) { store->mech = (mech_item *)tp; break; } } /* Default to a mechanism (probably on the internal token */ if (store->mech == 0) { store->mech = &dflt_mech; } } /* Generate a key and parameters to do the encryption */ #if NSS_VMAJOR >= 3 && (NSS_VMINOR <= 9 || (NSS_VMINOR <= 10 && NSS_VPATCH == 0)) store->key = PK11_KeyGen(store->slot, store->mech->type, 0, 0, 0); #else store->key = PK11_TokenKeyGenWithFlags(store->slot, store->mech->type, NULL, 0, NULL, CKF_ENCRYPT|CKF_DECRYPT, PR_FALSE, NULL); #endif if (store->key == 0) { /* PR_SetError(xxx); */ err = PIN_SYSTEMERROR; break; } store->params = PK11_GenerateNewParam(store->mech->type, store->key); if (store->params == 0) { err = PIN_SYSTEMERROR; break; } /* Compute the size of the encrypted data including necessary padding */ { int blocksize = PK11_GetBlockSize(store->mech->type, 0); store->length = strlen(pin)+1; /* Compute padded size - 0 means stream cipher */ if (blocksize != 0) { store->length += blocksize - (store->length % blocksize); } store->crypt = (unsigned char *)malloc(store->length); if (!store->crypt) { err = PIN_NOMEMORY; break; } } /* Encrypt */ { unsigned char *plain; PK11Context *ctx; SECStatus rv; int outLen; plain = (unsigned char *)malloc(store->length); if (!plain) { err = PIN_NOMEMORY; break; } /* Pad with 0 bytes */ memset(plain, 0, store->length); strcpy((char *)plain, pin); ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_ENCRYPT, store->key, store->params); if (!ctx) { err = PIN_SYSTEMERROR; break; } do { rv = PK11_CipherOp(ctx, store->crypt, &outLen, store->length, plain, store->length); if (rv) break; rv = PK11_Finalize(ctx); } while(0); PK11_DestroyContext(ctx, PR_TRUE); memset(plain, 0, store->length); free(plain); if (rv) err = PIN_SYSTEMERROR; } } while(0); if (err) { DestroyPk11PinStore(store); store = 0; } *out = store; return err; } /* * DestroyPk11PinStore */ void DestroyPk11PinStore(Pk11PinStore *store) { if (store == 0) return; if (store->params) { SECITEM_ZfreeItem(store->params, PR_TRUE); } if (store->key) { PK11_FreeSymKey(store->key); } if (store->crypt) { memset(store->crypt, 0, store->length); free(store->crypt); } free(store); } int Pk11StoreGetPin(char **out, Pk11PinStore *store) { int err = PIN_SUCCESS; unsigned char *plain; SECStatus rv = SECSuccess; PK11Context *ctx = 0; int outLen; do { plain = (unsigned char *)malloc(store->length); if (!plain) { err = PIN_NOMEMORY; break; } ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_DECRYPT, store->key, store->params); if (!ctx) { err = PIN_SYSTEMERROR; break; } rv = PK11_CipherOp(ctx, plain, &outLen, store->length, store->crypt, store->length); if (rv) break; rv = PK11_Finalize(ctx); if (rv) break; } while(0); if (ctx) PK11_DestroyContext(ctx, PR_TRUE); if (rv) { err = PIN_SYSTEMERROR; memset(plain, 0, store->length); free(plain); plain = 0; } *out = (char *)plain; return err; } int main(int argc, char ** argv) { SECStatus rv; PRFileDesc *in; PRFileDesc *out; PRPollDesc pd; PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; char buf[1024]; PRInt32 nBytes; char * command; char * tokenName; char * tokenpw; int fipsmode = 0; int semid = 0; union semun semarg; if (argc < 4 || argc > 5) { fprintf(stderr, "Usage: nss_pcache [prefix]\n"); exit(1); } signal(SIGHUP, SIG_IGN); semid = strtol(argv[1], NULL, 10); if (!strcasecmp(argv[2], "on")) fipsmode = 1; /* Initialize NSPR */ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); /* Set the PKCS #11 strings for the internal token. */ PK11_ConfigurePKCS11(NULL,NULL,NULL, INTERNAL_TOKEN_NAME, NULL, NULL,NULL,NULL,8,1); /* Initialize NSS and open the certificate database read-only. */ rv = NSS_Initialize(argv[3], argc == 5 ? argv[4] : NULL, argc == 5 ? argv[4] : NULL, "secmod.db", NSS_INIT_READONLY); if (rv != SECSuccess) { fprintf(stderr, "Unable to initialize NSS database: %d\n", rv); exit(1); } if (fipsmode) { if (!PK11_IsFIPS()) { char * internal_name = PR_smprintf("%s", SECMOD_GetInternalModule()->commonName); if ((SECMOD_DeleteInternalModule(internal_name) != SECSuccess) || !PK11_IsFIPS()) { NSS_Shutdown(); fprintf(stderr, "Unable to enable FIPS mode"); exit(1); } PR_smprintf_free(internal_name); } } in = PR_GetSpecialFD(PR_StandardInput); out = PR_GetSpecialFD(PR_StandardOutput); if (in == NULL || out == NULL) { fprintf(stderr, "PR_GetInheritedFD failed\n"); exit(1); } pd.fd = in; pd.in_flags = PR_POLL_READ | PR_POLL_EXCEPT; while (1) { rv = PR_Poll(&pd, 1, timeout); if (rv == -1) { /* PR_Poll failed */ break; } if (pd.out_flags & (PR_POLL_HUP | PR_POLL_ERR | PR_POLL_NVAL | PR_POLL_EXCEPT)) { break; } if (pd.out_flags & PR_POLL_READ) { memset(buf, 0, sizeof(buf)); nBytes = PR_Read(in, buf, sizeof(buf)); if (nBytes == -1 || nBytes == 0) { break; } command = getstr(buf, 0); tokenName = getstr(buf, 1); tokenpw = getstr(buf, 2); if (command && !strcmp(command, "QUIT")) { break; } else if (command && !strcmp(command, "STOR")) { PRInt32 err = PIN_SUCCESS; Node *node = NULL; if (tokenName && tokenpw) { node = (Node*)malloc(sizeof (Node)); if (!node) { err = PIN_NOMEMORY; } node->tokenName = strdup(tokenName); node->store = 0; node->next = 0; if (err == PIN_SUCCESS) err = CreatePk11PinStore(&node->store, tokenName, tokenpw); memset(tokenpw, 0, strlen(tokenpw)); } else err = PIN_SYSTEMERROR; sprintf(buf, "%d", err); PR_Write(out, buf, 1); if (err == PIN_SUCCESS) { if (pinList) node->next = pinList; pinList = node; } /* Now clean things up */ if (command) free(command); if (tokenName) free(tokenName); if (tokenpw) free(tokenpw); } else if (command && !strcmp(command, "RETR")) { Node *node; char *pin = 0; PRBool found = PR_FALSE; for (node = pinList; node != NULL; node = node->next) { if (!strcmp(node->tokenName, tokenName)) { if (Pk11StoreGetPin(&pin, node->store) == SECSuccess) { if (strlen(pin) == 0) PR_Write(out, "", 1); else PR_Write(out, pin, strlen(pin)); memset(pin, 0, strlen(pin)); free(pin); found = PR_TRUE; break; } } } if (found != PR_TRUE) PR_Write(out, "", 1); free(command); free(tokenName); } else { ; /* ack, unknown command */ } } } freeList(pinList); PR_Close(in); /* Remove the semaphore used for locking here. This is because this * program only goes away when Apache shuts down so we don't have to * worry about reloads. */ semctl(semid, 0, IPC_RMID, semarg); return 0; } /* * Given a \t-deliminated string, pick out the el-th element */ static char * getstr(const char * cmd, int el) { char *work, *s, *t, *r; char *peek; int i = 0; work = strdup(cmd); s = t = work; r = NULL; peek = s; if (peek) peek++; while (*s) { if (*s == '\t' || *s == '\0') { if (i == el) { if (*peek != '\0' || *s == '\t') *s = '\0'; r = strdup(t); free(work); return r; } else { /* not the element we want */ i++; s++; peek++; t = s; } } s++; peek++; } if (t) r = strdup(t); free(work); return r; } /* * Node implementation */ static void freeList(Node *list) { Node *n1; Node *n2; n1 = list; while (n1) { n2 = n1; if (n2->store) DestroyPk11PinStore(n2->store); if (n2->tokenName) free(n2->tokenName); n1 = n2->next; free(n2); } } mod_nss-1.0.12/nss_pcache.h000066400000000000000000000017221260357105600155230ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define PIN_SUCCESS 0 #define PIN_NOMEMORY 1 #define PIN_SYSTEMERROR 2 #define PIN_NOSUCHTOKEN 3 #define PIN_INCORRECTPW 4 typedef struct Pk11PinStore Pk11PinStore; int CreatePk11PinStore(Pk11PinStore **out, const char *tokenName, const char *pin); int Pk11StoreGetPin(char **out, Pk11PinStore *store); void DestroyPk11PinStore(Pk11PinStore *store); mod_nss-1.0.12/nss_util.c000066400000000000000000000101371260357105600152500ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mod_nss.h" #include "ap_mpm.h" #include "apr_thread_mutex.h" /* _________________________________________________________________ ** ** Utility Functions ** _________________________________________________________________ */ char *nss_util_vhostid(apr_pool_t *p, server_rec *s) { char *id; SSLSrvConfigRec *sc; char *host; apr_port_t port; host = s->server_hostname; if (s->port != 0) port = s->port; else { sc = mySrvConfig(s); if (sc->enabled == TRUE) port = DEFAULT_HTTPS_PORT; else port = DEFAULT_HTTP_PORT; } id = apr_psprintf(p, "%s:%lu", host, (unsigned long)port); return id; } apr_file_t *nss_util_ppopen(server_rec *s, apr_pool_t *p, const char *cmd, const char * const *argv) { apr_procattr_t *procattr; apr_proc_t *proc; if (apr_procattr_create(&procattr, p) != APR_SUCCESS) return NULL; if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK, APR_FULL_BLOCK) != APR_SUCCESS) return NULL; if (apr_procattr_dir_set(procattr, ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS) return NULL; if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS) return NULL; if ((proc = (apr_proc_t *)apr_pcalloc(p, sizeof(apr_proc_t))) == NULL) return NULL; if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS) return NULL; return proc->out; } void nss_util_ppclose(server_rec *s, apr_pool_t *p, apr_file_t *fp) { apr_file_close(fp); return; } /* * Run a filter program and read the first line of its stdout output */ char *nss_util_readfilter(server_rec *s, apr_pool_t *p, const char *cmd, const char * const *argv) { static char buf[MAX_STRING_LEN]; apr_file_t *fp; apr_size_t nbytes = 1; char c; int k; if ((fp = nss_util_ppopen(s, p, cmd, argv)) == NULL) return NULL; /* XXX: we are reading 1 byte at a time here */ for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) { if (c == '\n' || c == '\r') break; buf[k++] = c; } buf[k] = NUL; nss_util_ppclose(s, p, fp); return buf; } static void initializeHashVhostNick() { if (NULL != ht) return; apr_pool_create(&mp, NULL); ht = apr_hash_make(mp); } char *searchHashVhostbyNick(char *vhost_id) { char *searchVal = NULL; if (NULL == ht) return NULL; searchVal = apr_hash_get(ht, vhost_id, APR_HASH_KEY_STRING); return searchVal; } char *searchHashVhostbyNick_match(char *vhost_id) { char *searchValReg = NULL; apr_hash_index_t *hi; if (NULL == ht) return NULL; for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) { const char *k = NULL; const char *v = NULL; apr_hash_this(hi, (const void**)&k, NULL, (void**)&v); if (!ap_strcasecmp_match(vhost_id, k)) { searchValReg = apr_hash_get(ht, k, APR_HASH_KEY_STRING); return searchValReg; } } return NULL; } void addHashVhostNick(char *vhost_id, char *nickname) { if (ht == NULL) { initializeHashVhostNick(); } if (searchHashVhostbyNick(vhost_id) == NULL) { apr_hash_set(ht, apr_pstrdup(mp, vhost_id), APR_HASH_KEY_STRING, apr_pstrdup(mp, nickname)); } } mod_nss-1.0.12/test/000077500000000000000000000000001260357105600142215ustar00rootroot00000000000000mod_nss-1.0.12/test/README000066400000000000000000000022061260357105600151010ustar00rootroot00000000000000Overview -------- Some basic Apache tests using a local instance of Apache that goes into the work subdirectory. suite1.tmpl defines the basic configuration for the tests. This tries to load libmodnss.so from the parent directory so you must do a 'make' first before trying to run the tests. Run the tests ------------- ./setup.sh nosetests -v test.py Adding tests ------------ 1. Create a new Location in suite1.tmpl with a local configuration to test against. 2. Add a call to this location in test.py Here are the things that can be tested for: expected = HTTP response code or SSLError() exception protocol = cipher = OpenSSL cipher name 3. If you make a change to the mod_nss code you'll need to either copy the new module to work/httpd/lib or rm -rf work and re-run setup.sh otherwise you'll be testing against old code. When testing with NSSRequire I sometimes found it difficult to figure out why a request was being rejected. I added a new compile-time define, VAR_DEBUG. If this is set then whenever a SSL_ variable is looked up the result is logged. This is way too much for a running server but great for debugging tests. mod_nss-1.0.12/test/README.sni000066400000000000000000000016651260357105600157010ustar00rootroot00000000000000The SNI tests are overly complicated because of the sad state of affairs of pyOpenSSL. If I use the SSL client in http.client I can override some methods and have access to the negotiated protocol and cipher but don't have access to SNI. Or I can use the SSL client in urllib3.contrib and have working SNI but no access to the negotiated protocol or cipher. So I split the baby. When running the existing test suite I use the original override methods so I can continue to do cipher and protocol negotiation testing. When running the SNI tests I use the urllib3 SSL client and do only SNI testing. To run the tests: You need to edit /etc/hosts and add: your_ip_address www[1-25].example.com E.g. 192.168.0.1 www1.example.com 192.168.0.1 www2.example.com ... 192.168.0.1 www25.example.com Do not create www26 as that is used as a negative test. setup.sh and gencert have been extended to generate a bunch of certs suitable for SNI testing. mod_nss-1.0.12/test/createinstance.sh000077500000000000000000000037121260357105600175530ustar00rootroot00000000000000#!/bin/sh # # Make a temporary Apache instance for testing. function create_content_dirs { local dir=$1 mkdir $1 # Create the content mkdir $dir/rc4_cipher mkdir $dir/openssl_rc4_cipher mkdir $dir/openssl_aes_cipher mkdir $dir/acl mkdir $dir/protocolssl2 mkdir $dir/protocolssl3 mkdir $dir/protocoltls1 mkdir $dir/protocoltls11 mkdir $dir/protocoltls12 mkdir $dir/proxydata cat > $dir/index.html << EOF Basic index page for $dir conf/htpasswd << EOF /${dn}:xxj31ZMTZzkVA EOF # Create start/stop scripts cat << EOF > start #!/bin/sh MALLOC_CHECK_=3 MALLOC_PERTURB=9 HTTPD=/usr/sbin/httpd #valgrind --leak-check=full --log-file=valgrind.out.%p --trace-children=yes --track-origins=yes \$HTTPD -X -k start -d . -f ./conf/httpd.conf \$HTTPD -k start -d . -f ./conf/httpd.conf EOF cat << EOF > stop #!/bin/sh HTTPD=/usr/sbin/httpd \$HTTPD -k stop -d . -f ./conf/httpd.conf EOF chmod 0755 start stop mod_nss-1.0.12/test/httpd.conf.tmpl000066400000000000000000001026321260357105600171720ustar00rootroot00000000000000# # This is the main Apache HTTP server configuration file. It contains the # configuration directives that give the server its instructions. # See for detailed information. # In particular, see # # for a discussion of each configuration directive. # # Do NOT simply read the instructions in here without understanding # what they do. They're here only as hints or reminders. If you are unsure # consult the online docs. You have been warned. # # The configuration directives are grouped into three basic sections: # 1. Directives that control the operation of the Apache server process as a # whole (the 'global environment'). # 2. Directives that define the parameters of the 'main' or 'default' server, # which responds to requests that aren't handled by a virtual host. # These directives also provide default values for the settings # of all virtual hosts. # 3. Settings for virtual hosts, which allow Web requests to be sent to # different IP addresses or hostnames and have them handled by the # same Apache server process. # # Configuration and logfile names: If the filenames you specify for many # of the server's control files begin with "/" (or "drive:/" for Win32), the # server will use that explicit path. If the filenames do *not* begin # with "/", the value of ServerRoot is prepended -- so "logs/foo.log" # with ServerRoot set to "/etc/httpd" will be interpreted by the # server as "/etc/httpd/logs/foo.log". # ### Section 1: Global Environment # # The directives in this section affect the overall operation of Apache, # such as the number of concurrent requests it can handle or where it # can find its configuration files. # # # Don't give away too much information about all the subcomponents # we are running. Comment out this line if you don't mind remote sites # finding out what major optional modules you are running ServerTokens ProductOnly # # ServerRoot: The top of the directory tree under which the server's # configuration, error, and log files are kept. # # NOTE! If you intend to place this on an NFS (or otherwise network) # mounted filesystem then please read the LockFile documentation # (available at ); # you will save yourself a lot of trouble. # # Do NOT add a slash at the end of the directory path. # ServerRoot "::SERVER_ROOT::" # # PidFile: The file in which the server should record its process # identification number when it starts. Note the PIDFILE variable in # /etc/sysconfig/httpd must be set appropriately if this location is # changed. # PidFile run/httpd.pid # # Timeout: The number of seconds before receives and sends time out. # Timeout 60 # # KeepAlive: Whether or not to allow persistent connections (more than # one request per connection). Set to "Off" to deactivate. # KeepAlive Off # # MaxKeepAliveRequests: The maximum number of requests to allow # during a persistent connection. Set to 0 to allow an unlimited amount. # We recommend you leave this number high, for maximum performance. # MaxKeepAliveRequests 100 # # KeepAliveTimeout: Number of seconds to wait for the next request from the # same client on the same connection. # KeepAliveTimeout 5 ## ## Server-Pool Size Regulation (MPM specific) ## # prefork MPM # StartServers: number of server processes to start # MinSpareServers: minimum number of server processes which are kept spare # MaxSpareServers: maximum number of server processes which are kept spare # ServerLimit: maximum value for MaxClients for the lifetime of the server # MaxClients: maximum number of server processes allowed to start # MaxRequestsPerChild: maximum number of requests a server process serves StartServers 8 MinSpareServers 5 MaxSpareServers 20 ServerLimit 256 MaxClients 256 MaxRequestsPerChild 4000 # worker MPM # StartServers: initial number of server processes to start # MaxClients: maximum number of simultaneous client connections # MinSpareThreads: minimum number of worker threads which are kept spare # MaxSpareThreads: maximum number of worker threads which are kept spare # ThreadsPerChild: constant number of worker threads in each server process # MaxRequestsPerChild: maximum number of requests a server process serves StartServers 4 MaxClients 300 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 25 MaxRequestsPerChild 0 # # Listen: Allows you to bind Apache to specific IP addresses and/or # ports, instead of the default. See also the # directive. # # Change this to Listen on specific IP addresses as shown below to # prevent Apache from glomming onto all bound IP addresses. # #Listen 12.34.56.78:80 #Listen 80 # # Dynamic Shared Object (DSO) Support # # To be able to use the functionality of a module which was built as a DSO you # have to place corresponding `LoadModule' lines at this location so the # directives contained in it are actually available _before_ they are used. # Statically compiled modules (those listed by `httpd -l') do not need # to be loaded here. # # Example: # LoadModule foo_module modules/mod_foo.so # LoadModule access_compat_module modules/mod_access_compat.so LoadModule actions_module modules/mod_actions.so LoadModule alias_module modules/mod_alias.so LoadModule allowmethods_module modules/mod_allowmethods.so LoadModule auth_basic_module modules/mod_auth_basic.so #LoadModule auth_digest_module modules/mod_auth_digest.so LoadModule authn_anon_module modules/mod_authn_anon.so LoadModule authn_core_module modules/mod_authn_core.so LoadModule authn_dbd_module modules/mod_authn_dbd.so LoadModule authn_dbm_module modules/mod_authn_dbm.so LoadModule authn_file_module modules/mod_authn_file.so LoadModule authn_socache_module modules/mod_authn_socache.so LoadModule authz_core_module modules/mod_authz_core.so LoadModule authz_dbd_module modules/mod_authz_dbd.so LoadModule authz_dbm_module modules/mod_authz_dbm.so LoadModule authz_groupfile_module modules/mod_authz_groupfile.so LoadModule authz_host_module modules/mod_authz_host.so LoadModule authz_owner_module modules/mod_authz_owner.so LoadModule authz_user_module modules/mod_authz_user.so LoadModule autoindex_module modules/mod_autoindex.so LoadModule cache_module modules/mod_cache.so LoadModule cache_disk_module modules/mod_cache_disk.so LoadModule data_module modules/mod_data.so LoadModule dbd_module modules/mod_dbd.so LoadModule deflate_module modules/mod_deflate.so LoadModule dir_module modules/mod_dir.so LoadModule dumpio_module modules/mod_dumpio.so LoadModule echo_module modules/mod_echo.so LoadModule env_module modules/mod_env.so LoadModule expires_module modules/mod_expires.so LoadModule ext_filter_module modules/mod_ext_filter.so LoadModule filter_module modules/mod_filter.so LoadModule headers_module modules/mod_headers.so LoadModule include_module modules/mod_include.so LoadModule info_module modules/mod_info.so LoadModule log_config_module modules/mod_log_config.so LoadModule logio_module modules/mod_logio.so LoadModule macro_module modules/mod_macro.so LoadModule mime_magic_module modules/mod_mime_magic.so LoadModule mime_module modules/mod_mime.so LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule negotiation_module modules/mod_negotiation.so LoadModule remoteip_module modules/mod_remoteip.so LoadModule reqtimeout_module modules/mod_reqtimeout.so LoadModule rewrite_module modules/mod_rewrite.so LoadModule setenvif_module modules/mod_setenvif.so LoadModule slotmem_plain_module modules/mod_slotmem_plain.so LoadModule slotmem_shm_module modules/mod_slotmem_shm.so LoadModule socache_dbm_module modules/mod_socache_dbm.so LoadModule socache_memcache_module modules/mod_socache_memcache.so LoadModule socache_shmcb_module modules/mod_socache_shmcb.so LoadModule status_module modules/mod_status.so LoadModule substitute_module modules/mod_substitute.so LoadModule suexec_module modules/mod_suexec.so LoadModule unique_id_module modules/mod_unique_id.so LoadModule unixd_module modules/mod_unixd.so LoadModule userdir_module modules/mod_userdir.so LoadModule version_module modules/mod_version.so LoadModule vhost_alias_module modules/mod_vhost_alias.so # Include the locally-built NSS module LoadModule nss_module lib/libmodnss.so # Include the configuration we care about Include /etc/httpd/conf.modules.d/00-mpm.conf Include /etc/httpd/conf.modules.d/01-cgi.conf # # Load config files from the config directory "/etc/httpd/conf.d". # #Include conf.d/*.conf # # ExtendedStatus controls whether Apache will generate "full" status # information (ExtendedStatus On) or just basic information (ExtendedStatus # Off) when the "server-status" handler is called. The default is Off. # #ExtendedStatus On # # If you wish httpd to run as a different user or group, you must run # httpd as root initially and it will switch. # # User/Group: The name (or #number) of the user/group to run httpd as. # . On SCO (ODT 3) use "User nouser" and "Group nogroup". # . On HPUX you may not be able to use shared memory as nobody, and the # suggested workaround is to create a user www and use that user. # NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET) # when the value of (unsigned)Group is above 60000; # don't use Group #-1 on these systems! # User ::SERVER_UID:: Group ::SERVER_GID:: ### Section 2: 'Main' server configuration # # The directives in this section set up the values used by the 'main' # server, which responds to any requests that aren't handled by a # definition. These values also provide defaults for # any containers you may define later in the file. # # All of these directives may appear inside containers, # in which case these default settings will be overridden for the # virtual host being defined. # # # ServerAdmin: Your address, where problems with the server should be # e-mailed. This address appears on some server-generated pages, such # as error documents. e.g. admin@your-domain.com # ServerAdmin root@localhost # # ServerName gives the name and port that the server uses to identify itself. # This can often be determined automatically, but we recommend you specify # it explicitly to prevent problems during startup. # # If this is not set to valid DNS name for your host, server-generated # redirections will not work. See also the UseCanonicalName directive. # # If your host doesn't have a registered DNS name, enter its IP address here. # You will have to access it by its address anyway, and this will make # redirections work in a sensible way. # #ServerName www.example.com:80 ServerName localhost:::SERVER_PORT:: # # UseCanonicalName: Determines how Apache constructs self-referencing # URLs and the SERVER_NAME and SERVER_PORT variables. # When set "Off", Apache will use the Hostname and Port supplied # by the client. When set "On", Apache will use the value of the # ServerName directive. # UseCanonicalName On # # DocumentRoot: The directory out of which you will serve your # documents. By default, all requests are taken from this directory, but # symbolic links and aliases may be used to point to other locations. # DocumentRoot "::TEST_ROOT::/content" # # Each directory to which Apache has access can be configured with respect # to which services and features are allowed and/or disabled in that # directory (and its subdirectories). # # First, we configure the "default" to be a very restrictive set of # features. # Options FollowSymLinks AllowOverride None # # Note that from this point forward you must specifically allow # particular features to be enabled - so if something's not working as # you might expect, make sure that you have specifically enabled it # below. # # # This should be changed to whatever you set DocumentRoot to. # # # Possible values for the Options directive are "None", "All", # or any combination of: # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews # # Note that "MultiViews" must be named *explicitly* --- "Options All" # doesn't give it to you. # # The Options directive is both complicated and important. Please see # http://httpd.apache.org/docs/2.2/mod/core.html#options # for more information. # Options Indexes FollowSymLinks # # AllowOverride controls what directives may be placed in .htaccess files. # It can be "All", "None", or any combination of the keywords: # Options FileInfo AuthConfig Limit # AllowOverride All # # Controls who can get stuff from this server. # Order allow,deny Allow from all # # UserDir: The name of the directory that is appended onto a user's home # directory if a ~user request is received. # # The path to the end user account 'public_html' directory must be # accessible to the webserver userid. This usually means that ~userid # must have permissions of 711, ~userid/public_html must have permissions # of 755, and documents contained therein must be world-readable. # Otherwise, the client will only receive a "403 Forbidden" message. # # See also: http://httpd.apache.org/docs/misc/FAQ.html#forbidden # # # UserDir is disabled by default since it can confirm the presence # of a username on the system (depending on home directory # permissions). # UserDir disabled # # To enable requests to /~user/ to serve the user's public_html # directory, remove the "UserDir disabled" line above, and uncomment # the following line instead: # #UserDir public_html # # Control access to UserDir directories. The following is an example # for a site where these directories are restricted to read-only. # # # AllowOverride FileInfo AuthConfig Limit # Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec # # Order allow,deny # Allow from all # # # Order deny,allow # Deny from all # # # # DirectoryIndex: sets the file that Apache will serve if a directory # is requested. # # The index.html.var file (a type-map) is used to deliver content- # negotiated documents. The MultiViews Option can be used for the # same purpose, but it is much slower. # DirectoryIndex index.html index.html.var # # AccessFileName: The name of the file to look for in each directory # for additional configuration directives. See also the AllowOverride # directive. # AccessFileName .htaccess # # The following lines prevent .htaccess and .htpasswd files from being # viewed by Web clients. # Order allow,deny Deny from all Satisfy All # # TypesConfig describes where the mime.types file (or equivalent) is # to be found. # TypesConfig /etc/mime.types # # The mod_mime_magic module allows the server to use various hints from the # contents of the file itself to determine its type. The MIMEMagicFile # directive tells the module where the hint definitions are located. # # MIMEMagicFile /usr/share/magic.mime MIMEMagicFile conf/magic # # HostnameLookups: Log the names of clients or just their IP addresses # e.g., www.apache.org (on) or 204.62.129.132 (off). # The default is off because it'd be overall better for the net if people # had to knowingly turn this feature on, since enabling it means that # each client request will result in AT LEAST one lookup request to the # nameserver. # HostnameLookups Off # # EnableMMAP: Control whether memory-mapping is used to deliver # files (assuming that the underlying OS supports it). # The default is on; turn this off if you serve from NFS-mounted # filesystems. On some systems, turning it off (regardless of # filesystem) can improve performance; for details, please see # http://httpd.apache.org/docs/2.2/mod/core.html#enablemmap # #EnableMMAP off # # EnableSendfile: Control whether the sendfile kernel support is # used to deliver files (assuming that the OS supports it). # The default is on; turn this off if you serve from NFS-mounted # filesystems. Please see # http://httpd.apache.org/docs/2.2/mod/core.html#enablesendfile # #EnableSendfile off # # ErrorLog: The location of the error log file. # If you do not specify an ErrorLog directive within a # container, error messages relating to that virtual host will be # logged here. If you *do* define an error logfile for a # container, that host's errors will be logged there and not here. # ErrorLog logs/error_log # # LogLevel: Control the number of messages logged to the error_log. # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. # LogLevel debug # # The following directives define some format nicknames for use with # a CustomLog directive (see below). # LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent # "combinedio" includes actual counts of actual bytes received (%I) and sent (%O); this # requires the mod_logio module to be loaded. #LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio # # The location and format of the access logfile (Common Logfile Format). # If you do not define any access logfiles within a # container, they will be logged here. Contrariwise, if you *do* # define per- access logfiles, transactions will be # logged therein and *not* in this file. # #CustomLog logs/access_log common # # If you would like to have separate agent and referer logfiles, uncomment # the following directives. # #CustomLog logs/referer_log referer #CustomLog logs/agent_log agent # # For a single logfile with access, agent, and referer information # (Combined Logfile Format), use the following directive: # CustomLog logs/access_log combined # # Optionally add a line containing the server version and virtual host # name to server-generated pages (internal error documents, FTP directory # listings, mod_status and mod_info output etc., but not CGI generated # documents or custom error documents). # Set to "EMail" to also include a mailto: link to the ServerAdmin. # Set to one of: On | Off | EMail # ServerSignature Off # # Aliases: Add here as many aliases as you need (with no limit). The format is # Alias fakename realname # # Note that if you include a trailing / on fakename then the server will # require it to be present in the URL. So "/icons" isn't aliased in this # example, only "/icons/". If the fakename is slash-terminated, then the # realname must also be slash terminated, and if the fakename omits the # trailing slash, the realname must also omit it. # # We include the /icons/ alias for FancyIndexed directory listings. If you # do not use FancyIndexing, you may comment this out. # Alias /icons/ "/var/www/icons/" Options Indexes MultiViews FollowSymLinks AllowOverride None Order allow,deny Allow from all # # WebDAV module configuration section. # # Location of the WebDAV lock database. DAVLockDB /var/lib/dav/lockdb # # ScriptAlias: This controls which directories contain server scripts. # ScriptAliases are essentially the same as Aliases, except that # documents in the realname directory are treated as applications and # run by the server when requested rather than as documents sent to the client. # The same rules about trailing "/" apply to ScriptAlias directives as to # Alias. # ScriptAlias /cgi-bin/ "::TEST_ROOT::/cgi-bin/" # # "/var/www/cgi-bin" should be changed to whatever your ScriptAliased # CGI directory exists, if you have that configured. # AllowOverride None Options None Order allow,deny Allow from all # # Redirect allows you to tell clients about documents which used to exist in # your server's namespace, but do not anymore. This allows you to tell the # clients where to look for the relocated document. # Example: # Redirect permanent /foo http://www.example.com/bar # # Directives controlling the display of server-generated directory listings. # # # IndexOptions: Controls the appearance of server-generated directory # listings. # IndexOptions FancyIndexing VersionSort NameWidth=* HTMLTable Charset=UTF-8 # # AddIcon* directives tell the server which icon to show for different # files or filename extensions. These are only displayed for # FancyIndexed directories. # AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip AddIconByType (TXT,/icons/text.gif) text/* AddIconByType (IMG,/icons/image2.gif) image/* AddIconByType (SND,/icons/sound2.gif) audio/* AddIconByType (VID,/icons/movie.gif) video/* AddIcon /icons/binary.gif .bin .exe AddIcon /icons/binhex.gif .hqx AddIcon /icons/tar.gif .tar AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip AddIcon /icons/a.gif .ps .ai .eps AddIcon /icons/layout.gif .html .shtml .htm .pdf AddIcon /icons/text.gif .txt AddIcon /icons/c.gif .c AddIcon /icons/p.gif .pl .py AddIcon /icons/f.gif .for AddIcon /icons/dvi.gif .dvi AddIcon /icons/uuencoded.gif .uu AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl AddIcon /icons/tex.gif .tex AddIcon /icons/bomb.gif core AddIcon /icons/back.gif .. AddIcon /icons/hand.right.gif README AddIcon /icons/folder.gif ^^DIRECTORY^^ AddIcon /icons/blank.gif ^^BLANKICON^^ # # DefaultIcon is which icon to show for files which do not have an icon # explicitly set. # DefaultIcon /icons/unknown.gif # # AddDescription allows you to place a short description after a file in # server-generated indexes. These are only displayed for FancyIndexed # directories. # Format: AddDescription "description" filename # #AddDescription "GZIP compressed document" .gz #AddDescription "tar archive" .tar #AddDescription "GZIP compressed tar archive" .tgz # # ReadmeName is the name of the README file the server will look for by # default, and append to directory listings. # # HeaderName is the name of a file which should be prepended to # directory indexes. ReadmeName README.html HeaderName HEADER.html # # IndexIgnore is a set of filenames which directory indexing should ignore # and not include in the listing. Shell-style wildcarding is permitted. # IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t # # DefaultLanguage and AddLanguage allows you to specify the language of # a document. You can then use content negotiation to give a browser a # file in a language the user can understand. # # Specify a default language. This means that all data # going out without a specific language tag (see below) will # be marked with this one. You probably do NOT want to set # this unless you are sure it is correct for all cases. # # * It is generally better to not mark a page as # * being a certain language than marking it with the wrong # * language! # # DefaultLanguage nl # # Note 1: The suffix does not have to be the same as the language # keyword --- those with documents in Polish (whose net-standard # language code is pl) may wish to use "AddLanguage pl .po" to # avoid the ambiguity with the common suffix for perl scripts. # # Note 2: The example entries below illustrate that in some cases # the two character 'Language' abbreviation is not identical to # the two character 'Country' code for its country, # E.g. 'Danmark/dk' versus 'Danish/da'. # # Note 3: In the case of 'ltz' we violate the RFC by using a three char # specifier. There is 'work in progress' to fix this and get # the reference data for rfc1766 cleaned up. # # Catalan (ca) - Croatian (hr) - Czech (cs) - Danish (da) - Dutch (nl) # English (en) - Esperanto (eo) - Estonian (et) - French (fr) - German (de) # Greek-Modern (el) - Hebrew (he) - Italian (it) - Japanese (ja) # Korean (ko) - Luxembourgeois* (ltz) - Norwegian Nynorsk (nn) # Norwegian (no) - Polish (pl) - Portugese (pt) # Brazilian Portuguese (pt-BR) - Russian (ru) - Swedish (sv) # Simplified Chinese (zh-CN) - Spanish (es) - Traditional Chinese (zh-TW) # AddLanguage ca .ca AddLanguage cs .cz .cs AddLanguage da .dk AddLanguage de .de AddLanguage el .el AddLanguage en .en AddLanguage eo .eo AddLanguage es .es AddLanguage et .et AddLanguage fr .fr AddLanguage he .he AddLanguage hr .hr AddLanguage it .it AddLanguage ja .ja AddLanguage ko .ko AddLanguage ltz .ltz AddLanguage nl .nl AddLanguage nn .nn AddLanguage no .no AddLanguage pl .po AddLanguage pt .pt AddLanguage pt-BR .pt-br AddLanguage ru .ru AddLanguage sv .sv AddLanguage zh-CN .zh-cn AddLanguage zh-TW .zh-tw # # LanguagePriority allows you to give precedence to some languages # in case of a tie during content negotiation. # # Just list the languages in decreasing order of preference. We have # more or less alphabetized them here. You probably want to change this. # LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW # # ForceLanguagePriority allows you to serve a result page rather than # MULTIPLE CHOICES (Prefer) [in case of a tie] or NOT ACCEPTABLE (Fallback) # [in case no accepted languages matched the available variants] # ForceLanguagePriority Prefer Fallback # # Specify a default charset for all content served; this enables # interpretation of all content as UTF-8 by default. To use the # default browser choice (ISO-8859-1), or to allow the META tags # in HTML content to override this choice, comment out this # directive: # AddDefaultCharset UTF-8 # # AddType allows you to add to or override the MIME configuration # file mime.types for specific file types. # #AddType application/x-tar .tgz # # AddEncoding allows you to have certain browsers uncompress # information on the fly. Note: Not all browsers support this. # Despite the name similarity, the following Add* directives have nothing # to do with the FancyIndexing customization directives above. # #AddEncoding x-compress .Z #AddEncoding x-gzip .gz .tgz .svgz # If the AddEncoding directives above are commented-out, then you # probably should define those extensions to indicate media types: # AddType application/x-compress .Z AddType application/x-gzip .gz .tgz # # MIME-types for downloading Certificates and CRLs # AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl # # AddHandler allows you to map certain file extensions to "handlers": # actions unrelated to filetype. These can be either built into the server # or added with the Action directive (see below) # # To use CGI scripts outside of ScriptAliased directories: # (You will also need to add "ExecCGI" to the "Options" directive.) # #AddHandler cgi-script .cgi # # For files that include their own HTTP headers: # #AddHandler send-as-is asis # # For type maps (negotiated resources): # (This is enabled by default to allow the Apache "It Worked" page # to be distributed in multiple languages.) # AddHandler type-map var # # Filters allow you to process content before it is sent to the client. # # To parse .shtml files for server-side includes (SSI): # (You will also need to add "Includes" to the "Options" directive.) # AddType text/html .shtml AddOutputFilter INCLUDES .shtml # # Action lets you define media types that will execute a script whenever # a matching file is called. This eliminates the need for repeated URL # pathnames for oft-used CGI file processors. # Format: Action media/type /cgi-script/location # Format: Action handler-name /cgi-script/location # # # Customizable error responses come in three flavors: # 1) plain text 2) local redirects 3) external redirects # # Some examples: #ErrorDocument 500 "The server made a boo boo." #ErrorDocument 404 /missing.html #ErrorDocument 404 "/cgi-bin/missing_handler.pl" #ErrorDocument 402 http://www.example.com/subscription_info.html # # # Putting this all together, we can internationalize error responses. # # We use Alias to redirect any /error/HTTP_.html.var response to # our collection of by-error message multi-language collections. We use # includes to substitute the appropriate text. # # You can modify the messages' appearance without changing any of the # default HTTP_.html.var files by adding the line: # # Alias /error/include/ "/your/include/path/" # # which allows you to create your own set of files by starting with the # /var/www/error/include/ files and # copying them to /your/include/path/, even on a per-VirtualHost basis. # Alias /error/ "/var/www/error/" AllowOverride None Options IncludesNoExec AddOutputFilter Includes html AddHandler type-map var Order allow,deny Allow from all LanguagePriority en es de fr ForceLanguagePriority Prefer Fallback # ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var # ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var # ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var # ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var # ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var # ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var # ErrorDocument 410 /error/HTTP_GONE.html.var # ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var # ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var # ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var # ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var # ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var # ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var # ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var # ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var # ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var # ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var # # The following directives modify normal HTTP response behavior to # handle known problems with browser implementations. # BrowserMatch "Mozilla/2" nokeepalive BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 BrowserMatch "RealPlayer 4\.0" force-response-1.0 BrowserMatch "Java/1\.0" force-response-1.0 BrowserMatch "JDK/1\.0" force-response-1.0 # # The following directive disables redirects on non-GET requests for # a directory that does not include the trailing slash. This fixes a # problem with Microsoft WebFolders which does not appropriately handle # redirects for folders with DAV methods. # Same deal with Apple's DAV filesystem and Gnome VFS support for DAV. # BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully BrowserMatch "MS FrontPage" redirect-carefully BrowserMatch "^WebDrive" redirect-carefully BrowserMatch "^WebDAVFS/1.[0123]" redirect-carefully BrowserMatch "^gnome-vfs/1.0" redirect-carefully BrowserMatch "^XML Spy" redirect-carefully BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully # # Allow server status reports generated by mod_status, # with the URL of http://servername/server-status # Change the ".example.com" to match your domain to enable. # # # SetHandler server-status # Order deny,allow # Deny from all # Allow from .example.com # # # Allow remote server configuration reports, with the URL of # http://servername/server-info (requires that mod_info.c be loaded). # Change the ".example.com" to match your domain to enable. # # # SetHandler server-info # Order deny,allow # Deny from all # Allow from .example.com # # # Proxy Server directives. Uncomment the following lines to # enable the proxy server: # # #ProxyRequests On # # # Order deny,allow # Deny from all # Allow from .example.com # # # Enable/disable the handling of HTTP/1.1 "Via:" headers. # ("Full" adds the server version; "Block" removes all outgoing Via: headers) # Set to one of: Off | On | Full | Block # #ProxyVia On # # To enable a cache of proxied content, uncomment the following lines. # See http://httpd.apache.org/docs/2.2/mod/mod_cache.html for more details. # # # CacheEnable disk / # CacheRoot "/var/cache/mod_proxy" # # # # End of proxy directives. ### Section 3: Virtual Hosts # # VirtualHost: If you want to maintain multiple domains/hostnames on your # machine you can setup VirtualHost containers for them. Most configurations # use only name-based virtual hosts so the server doesn't need to worry about # IP addresses. This is indicated by the asterisks in the directives below. # # Please see the documentation at # # for further details before you try to setup virtual hosts. # # You may use the command line option '-S' to verify your virtual host # configuration. # # Use name-based virtual hosting. # #NameVirtualHost *:80 # # NOTE: NameVirtualHost cannot be used without a port specifier # (e.g. :80) if mod_ssl is being used, due to the nature of the # SSL protocol. # # # VirtualHost example: # Almost any Apache directive may go into a VirtualHost container. # The first VirtualHost section is used for requests without a known # server name. # # # ServerAdmin webmaster@dummy-host.example.com # DocumentRoot /www/docs/dummy-host.example.com # ServerName dummy-host.example.com # ErrorLog logs/dummy-host.example.com-error_log # CustomLog logs/dummy-host.example.com-access_log common # Include conf/test.conf mod_nss-1.0.12/test/printenv.pl000077500000000000000000000002551260357105600164300ustar00rootroot00000000000000#!/usr/bin/perl binmode(STDOUT); binmode(STDIN); print "Content-Type: text/plain\r\n"; print "\r\n"; foreach $key (sort (keys (%ENV))) { print "$key=$ENV{$key}\n"; } mod_nss-1.0.12/test/setup.sh000077500000000000000000000042161260357105600157230ustar00rootroot00000000000000#!/bin/sh currentpath=`pwd` server_uid=$USER server_gid=$USER server_port=8000 server_name=`hostname` while [[ $# > 1 ]] do key="$1" case $key in -s|--sni) SNI="$2" shift # past argument ;; *) # unknown option ;; esac shift # past argument or value done DBPREFIX=$1 test_root=$currentpath/work/httpd test_root_esc=`echo ${test_root} | sed -e 's/\\//\\\\\\//g'` if [ -e $test_root ]; then if [ $# -gt 0 -a "$1X" = "forceX" ]; then rm -rf work else echo "Test directory already exists" exit 1 fi fi ./createinstance.sh ${test_root} cp printenv.pl ${test_root}/cgi-bin chmod 755 ${test_root}/cgi-bin/printenv.pl cp ../.libs/libmodnss.so ${test_root}/lib cp ../nss_pcache ${test_root}/bin echo "Generating a new certificate database..." bash ../gencert ${DBPREFIX}${test_root}/alias $SNI > /dev/null 2>&1 echo internal:httptest > ${test_root}/conf/password.conf # Export the CA cert certutil -L -d ${DBPREFIX}${test_root}/alias -n cacert -a > ${test_root}/alias/ca.pem # Export the client cert cd ${test_root} echo password > pw echo httptest > dbpw pk12util -o alpha.p12 -d ${DBPREFIX}${test_root}/alias -n alpha -w pw -k dbpw openssl pkcs12 -in alpha.p12 -clcerts -nokeys -out alpha.crt -passin pass:`cat pw` openssl pkcs12 -in alpha.p12 -nocerts -nodes -out alpha.key -passin pass:`cat pw` pk12util -o beta.p12 -d ${DBPREFIX}${test_root}/alias -n beta -w pw -k dbpw openssl pkcs12 -in beta.p12 -clcerts -nokeys -out beta.crt -passin pass:`cat pw` openssl pkcs12 -in beta.p12 -nocerts -nodes -out beta.key -passin pass:`cat pw` /bin/rm -f pw dbpw cd - if [ -f ${test_root}/sedfile ] then rm ${test_root}/sedfile fi echo "s/::TEST_ROOT::/${test_root_esc}/g" >> ${test_root}/sedfile echo "s/::SERVER_ROOT::/${test_root_esc}/g" >> ${test_root}/sedfile echo "s/::SERVER_PORT::/${server_port}/g" >> ${test_root}/sedfile echo "s/::SERVER_NAME::/${server_name}/g" >> ${test_root}/sedfile echo "s/::SERVER_UID::/${server_uid}/g" >> ${test_root}/sedfile echo "s/::SERVER_GID::/${server_gid}/g" >> ${test_root}/sedfile cat httpd.conf.tmpl | sed -f ${test_root}/sedfile > ${test_root}/conf/httpd.conf mod_nss-1.0.12/test/sni.tmpl000066400000000000000000000011751260357105600157140ustar00rootroot00000000000000 ServerName $SNINAME DocumentRoot $SERVER_ROOT/sni$SNINUM NSSEngine on NSSFIPS off NSSOCSP off NSSRenegotiation on NSSCipherSuite +aes_128_sha_256,+aes_256_sha_256,+rsa_aes_128_gcm_sha_256 NSSProtocol TLSv1.2 NSSNickname Server-Cert-$SNINAME NSSVerifyClient none # A bit redundant since the initial handshake should fail if no TLSv1.2 NSSRequire %{SSL_PROTOCOL} eq "TLSv1.2" NSSOptions +ExportCertData +CompatEnvVars +StdEnvVars mod_nss-1.0.12/test/suite1.tmpl000066400000000000000000000076051260357105600163410ustar00rootroot00000000000000# Global SSL configuration NSSPassPhraseDialog file:$SERVER_ROOT/conf/password.conf NSSPassPhraseHelper $SERVER_ROOT/bin/nss_pcache NSSSessionCacheSize 10000 NSSSessionCacheTimeout 100 NSSSession3CacheTimeout 86400 Listen 0.0.0.0:$SERVER_PORT Listen 0.0.0.0:8001 LogLevel debug CoreDumpDirectory $SERVER_ROOT ServerName $SERVER_NAME DocumentRoot $SERVER_ROOT/content NSSSNI $SNI NSSEngine on NSSFIPS off NSSOCSP off NSSRenegotiation on NSSCipherSuite +rsa_rc4_128_md5,+rsa_3des_sha,+rsa_des_sha,+rsa_aes_128_sha,+rsa_aes_256_sha NSSProtocol SSLv3,TLSv1.0 NSSNickname Server-Cert NSSCertificateDatabase $DBPREFIX$SERVER_ROOT/alias NSSVerifyClient none NSSUserName SSL_CLIENT_S_DN_UID NSSCipherSuite +rsa_rc4_128_md5 NSSCipherSuite RC4-SHA # In openssl equivalent of AES:-ECDH:-ADH:-PSK:-DH # In NSS equivalent of AES:-ECDH NSSCipherSuite AES+RSA NSSOptions +StdEnvVars +CompatEnvVars +ExportCertData NSSVerifyClient require NSSOptions +StdEnvVars +CompatEnvVars +ExportCertData NSSVerifyClient require NSSRequire ( %{SSL_CLIENT_S_DN_UID} eq "alpha" \ or %{SSL_CLIENT_S_DN_UID} eq "gamma" ) \ and %{SSL_CLIENT_S_DN_O} eq "example.com" \ and %{SSL_CLIENT_S_DN_OU} eq "People" NSSOptions +StdEnvVars +CompatEnvVars +ExportCertData +FakeBasicAuth NSSVerifyClient require AuthType Basic AuthName Cert AuthUserFile conf/htpasswd Require valid-user NSSRequire %{SSL_CIPHER_USEKEYSIZE} > 40 NSSRequire %{SSL_CIPHER_USEKEYSIZE} > 4000 NSSRequire %{SSL_PROTOCOL} eq "SSLv3" NSSRequire %{SSL_PROTOCOL} eq "TLSv1" NSSRequire %{SSL_PROTOCOL} eq "TLSv1.1" NSSRequire %{SSL_PROTOCOL} eq "TLSv1.2" NSSOptions +ExportCertData +CompatEnvVars +StdEnvVars NSSProxyEngine on NSSProxyCipherSuite +rsa_rc4_128_md5,+rsa_3des_sha,+rsa_des_sha,+rsa_aes_128_sha,+rsa_aes_256_sha NSSProxyProtocol TLSv1.0,TLSv1.2 ProxyPreserveHost $PRESERVEHOST ProxyPass /proxy https://www1.example.com:8000/proxydata ProxyPassReverse /proxy https://www1.example.com:8000/proxydata # # For testing protocol handling # ServerName $SERVER_NAME DocumentRoot $SERVER_ROOT/content NSSEngine on NSSFIPS off NSSOCSP off NSSRenegotiation on NSSCipherSuite +aes_128_sha_256,+aes_256_sha_256,+rsa_aes_128_gcm_sha_256 NSSProtocol TLSv1.2 NSSNickname Server-Cert NSSVerifyClient none # A bit redundant since the initial handshake should fail if no TLSv1.2 NSSRequire %{SSL_PROTOCOL} eq "TLSv1.2" NSSOptions +ExportCertData +CompatEnvVars +StdEnvVars # # SNI testing. Requires that you add an entry like this to /etc/hosts: # # www1.example.com # # 25 of these are needed # # Test with something like: # curl --cacert alias/ca.pem -v https://www1.example.com:8000/index.html # # Output should be something like: Basic index page for sni1 # include conf.d/* mod_nss-1.0.12/test/test.py000066400000000000000000000177071260357105600155660ustar00rootroot00000000000000from test_config import Declarative, write_template_file, restart_apache from test_config import stop_apache import ssl import requests.exceptions import os try: # python3.2+ from ssl import CertificateError except ImportError: try: # Older python where the backport from pypi is installed from backports.ssl_match_hostname import CertificateError except ImportError: # Other older python we use the urllib3 bundled copy from urllib3.packages.ssl_match_hostname import CertificateError class test_suite1(Declarative): @classmethod def setUpClass(cls): write_template_file('suite1.tmpl', 'work/httpd/conf/test.conf', {'DBPREFIX': os.environ.get('DBPREFIX', ''), 'SNI': 'off', 'PRESERVEHOST': 'Off', } ) # Generate a single VH to do negative SNI testing write_template_file('sni.tmpl', 'work/httpd/conf.d/sni1.conf', {'DBPREFIX': os.environ.get('DBPREFIX', ''), 'SNINAME': 'www1.example.com', 'SNINUM': 1, } ) restart_apache() @classmethod def tearDownClass(cls): stop_apache() tests = [ dict( desc='Basic SSL connection', request=('/', {}), expected=200, ), dict( desc='Basic SSL connection, 404', request=('/notfound', {}), expected=404, ), dict( desc='SSL connection, fail to verify', request=('/', {'verify': True}), expected=requests.exceptions.SSLError(), expected_str='certificate verify failed', ), dict( desc='SSL AES128-SHA cipher check', request=('/index.html', {}), expected=200, cipher='AES128-SHA', ), dict( desc='Default protocol check', request=('/', {}), expected=200, protocol='TLSv1/SSLv3', ), dict( desc='server-side RC4 cipher check', request=('/rc4_cipher/', {'ciphers': 'ALL'}), expected=200, cipher='RC4-MD5', ), dict( desc='client-side cipher check', request=('/', {'ciphers': 'AES256-SHA'}), expected=200, cipher='AES256-SHA', ), dict( desc='server-side OpenSSL-style RC4 cipher check', request=('/openssl_rc4_cipher/', {'ciphers': 'ALL'}), expected=200, ), dict( desc='server-side OpenSSL-style AES cipher check', request=('/openssl_aes_cipher/', {'ciphers': 'AES128-SHA'}), expected=200, ), dict( desc='Basic client auth, no certificate', request=('/acl/aclS01.html', {}), expected=requests.exceptions.SSLError(), ), dict( desc='Basic client auth, valid certificate', request=('/acl/aclS01.html', { 'key_file': 'work/httpd/alpha.key', 'cert_file': 'work/httpd/alpha.crt',} ), expected=200, ), dict( desc='NSSRequire auth, no certificate', request=('/acl/aclS02.html', {}), expected=requests.exceptions.SSLError(), ), dict( desc='NSSRequire auth, valid certificate', request=('/acl/aclS02.html', { 'key_file': 'work/httpd/alpha.key', 'cert_file': 'work/httpd/alpha.crt',} ), expected=200, ), dict( desc='NSSRequire auth, not allowed certificate', request=('/acl/aclS02.html', { 'key_file': 'work/httpd/beta.key', 'cert_file': 'work/httpd/beta.crt',} ), expected=403, ), dict( desc='FakeBasicAuth, no certificate', request=('/acl/aclS03.html', {}), expected=requests.exceptions.SSLError(), ), dict( desc='FakeBasicAuth, valid certificate', request=('/acl/aclS03.html', { 'key_file': 'work/httpd/alpha.key', 'cert_file': 'work/httpd/alpha.crt',} ), expected=200, ), dict( desc='FakeBasicAuth, not allowed user', request=('/acl/aclS03.html', { 'key_file': 'work/httpd/beta.key', 'cert_file': 'work/httpd/beta.crt',} ), expected=401, ), dict( desc='Secret key size', request=('/secret-test.html', {}), expected=200, ), dict( desc='Impossible secret key size', request=('/secret-test-impossible.html', {}), expected=403, ), # Only SSLv3-TLSv1.1 enabled on 8000 dict( desc='Requires TLS v1.2, no support', request=('/protocoltls12/index.html', {}), expected=403, ), dict( desc='Try SSLv2 on default server', request=('/protocoltls12/index.html', {'ssl_version': ssl.PROTOCOL_SSLv2} ), expected=requests.exceptions.SSLError(), ), dict( desc='Try SSLv23 client on SSLv3 location', request=('/protocolssl3/index.html', {'ssl_version': ssl.PROTOCOL_SSLv23} ), expected=403, # connects as TLSv1 ), dict( desc='Try TLSv1 client on SSLv3 location', request=('/protocoltls1/index.html', {'ssl_version': ssl.PROTOCOL_TLSv1} ), expected=200, ), dict( desc='Try TLSv1 client on TLSv1.1 location', request=('/protocoltls11/index.html', {'ssl_version': ssl.PROTOCOL_TLSv1} ), expected=403, ), dict( desc='Try SSLv23 client on TLSv1 location', request=('/protocoltls1/index.html', {'ssl_version': ssl.PROTOCOL_SSLv23} ), expected=200, ), dict( desc='Try SSLv23 client on 1.2-only location', request=('/protocoltls12/index.html', {'ssl_version': ssl.PROTOCOL_SSLv23} ), expected=403, ), dict( desc='Requires TLSv1.2 on VH that provides it', request=('/protocoltls12/index.html', {'port': 8001}), expected=200, ), dict( desc='Try SSLv2 client on 1.2-only VH', request=('/protocoltls12/index.html', {'port': 8001, 'ssl_version': ssl.PROTOCOL_SSLv2} ), expected=requests.exceptions.SSLError(), ), dict( desc='Try SSLv3 client on 1.2-only VH', request=('/protocoltls12/index.html', {'port': 8001, 'ssl_version': ssl.PROTOCOL_SSLv3} ), expected=requests.exceptions.SSLError(), ), dict( desc='Try TLSv1 client on 1.2-only VH', request=('/protocoltls12/index.html', {'port': 8001, 'ssl_version': ssl.PROTOCOL_TLSv1} ), expected=requests.exceptions.SSLError(), ), dict( desc='SNI request when SNI is disabled', request=('/index.html', {'host': 'www1.example.com', 'port': 8000} ), expected=requests.exceptions.SSLError(), expected_str='doesn\'t match', ), dict( desc='Reverse proxy request when SNI is disabled', request=('/proxy/index.html', {}), expected=400, ), ] mod_nss-1.0.12/test/test_cipher.py000066400000000000000000000206721260357105600171130ustar00rootroot00000000000000from test_util import run, assert_equal import os import nose from nose.tools import make_decorator # This file is auto-generated by configure from variable import ENABLE_SHA384, ENABLE_GCM cwd = os.getcwd() srcdir = os.path.dirname(cwd) exe = "%s/test_cipher" % srcdir openssl = "/usr/bin/openssl" ciphernum = 0 CIPHERS_NOT_IN_NSS = ['ECDH-RSA-AES128-SHA256', 'ECDH-ECDSA-AES128-GCM-SHA256', 'ECDH-ECDSA-AES128-SHA256', 'ECDH-RSA-AES128-GCM-SHA256', 'EXP-DES-CBC-SHA', 'ECDH-RSA-AES256-GCM-SHA384', 'ECDH-ECDSA-AES256-SHA384', 'ECDH-RSA-AES256-SHA384', 'ECDH-ECDSA-AES256-GCM-SHA384', ] def assert_equal_openssl(nss_ciphers, ossl_ciphers): (nss, err, rc) = run([exe, "--o", nss_ciphers]) assert rc == 0 (ossl, err, rc) = run([openssl, "ciphers", ossl_ciphers]) assert rc == 0 nss_list = nss.strip().split(':') nss_list.sort() ossl_list = ossl.strip().split(':') ossl_list = list(set(ossl_list)) ossl_list.sort() # NSS doesn't support the SHA-384 ciphers, remove them from the OpenSSL # output. t = list() for o in ossl_list: if not ENABLE_SHA384 and 'SHA384' in o: continue if not ENABLE_GCM and 'GCM' in o: continue if o in CIPHERS_NOT_IN_NSS: continue t.append(o) ossl_list = t if len(nss_list) > len(ossl_list): diff = set(nss_list) - set(ossl_list) elif len(ossl_list) > len(nss_list): diff = set(ossl_list) - set(nss_list) else: diff = '' assert nss_list == ossl_list, '%r != %r. Difference %r' % (':'.join(nss_list), ':'.join(ossl_list), diff) def assert_no_NULL(nss_ciphers): (nss, err, rc) = run([exe, "--o", nss_ciphers]) assert rc == 0 assert('NULL' not in nss) class test_ciphers(object): @classmethod def setUpClass(cls): (out, err, rc) = run([exe, "--count"]) assert rc == 0 cls.ciphernum = int(out) def test_RSA(self): assert_equal_openssl("RSA", "RSA:-SSLv2:-SEED:-IDEA") def test_kRSA(self): assert_equal_openssl("kRSA", "kRSA:-SSLv2:-SEED:-IDEA") def test_aRSA(self): assert_equal_openssl("aRSA", "aRSA:-SSLv2:-SEED:-IDEA:-DH") def test_EDH(self): # No DH ciphers supported yet (out, err, rc) = run([exe, "EDH"]) assert rc == 1 def test_RC4(self): assert_equal_openssl("RC4", "RC4:-KRB5:-PSK:-ADH") def test_RC2(self): assert_equal_openssl("RC2", "RC2:-SSLv2:-KRB5") def test_AES(self): assert_equal_openssl("AES", "AES:-PSK:-ADH:-DSS:-DH") def test_AESGCM(self): assert_equal_openssl("AESGCM", "AESGCM:-PSK:-ADH:-DSS:-DH") def test_AES128(self): assert_equal_openssl("AES128", "AES128:-PSK:-ADH:-DSS:-DH") def test_AES256(self): assert_equal_openssl("AES256", "AES256:-PSK:-ADH:-DSS:-DH") def test_CAMELLIA(self): assert_equal_openssl("CAMELLIA", "CAMELLIA:-DH") def test_CAMELLIA128(self): assert_equal_openssl("CAMELLIA128", "CAMELLIA128:-DH") def test_CAMELLIA256(self): assert_equal_openssl("CAMELLIA256", "CAMELLIA256:-DH") def test_3DES(self): assert_equal_openssl("3DES", "3DES:-SSLv2:-PSK:-KRB5:-DH") def test_DES(self): assert_equal_openssl("DES", "DES:-SSLv2:-KRB5:-DH") def test_ALL(self): assert_equal_openssl("ALL", "ALL:-SSLv2:-KRB5:-ADH:-DH:-DSS:-PSK:-SEED:-IDEA") def test_ALL_no_AES(self): assert_equal_openssl("ALL:-AES", "ALL:-AES:-SSLv2:-KRB5:-ADH:-DH:-DSS:-PSK:-SEED:-IDEA") def test_COMPLEMENTOFALL(self): assert_equal_openssl("COMPLEMENTOFALL", "COMPLEMENTOFALL") # skipping DEFAULT as we use the NSS defaults # skipping COMPLEMENTOFDEFAULT as these are all ADH ciphers def test_SSLv3(self): assert_equal_openssl("SSLv3", "SSLv3:-KRB5:-PSK:-ADH:-EDH:-DH:-SEED:-IDEA") def test_SSLv3_equals_TLSv1(self): (nss, err, rc) = run([exe, "--o", "SSLv3"]) (nss2, err, rc2) = run([exe, "--o", "TLSv1"]) assert rc == 0 assert rc2 == 0 assert_equal(nss, nss2) def test_TLSv12(self): assert_equal_openssl("TLSv1.2", "TLSv1.2:TLSv1.2:-ADH:-DH:-DSS") def test_NULL(self): assert_equal_openssl("NULL", "NULL") def test_nss_rsa_rc4_128(self): # Test NSS cipher parsing (out, err, rc) = run([exe, "+rsa_rc4_128_md5,+rsa_rc4_128_sha"]) assert rc == 0 assert_equal(out, 'rsa_rc4_128_md5, rsa_rc4_128_sha') def test_EXP(self): assert_equal_openssl("EXP", "EXP:-SSLv2:-DH:-KRB5") def test_EXPORT(self): assert_equal_openssl("EXPORT", "EXPORT:-SSLv2:-DH:-KRB5") def test_EXPORT40(self): assert_equal_openssl("EXPORT40", "EXPORT40:-SSLv2:-ADH:-DH:-KRB5") def test_MD5(self): assert_equal_openssl("MD5", "MD5:-SSLv2:-DH:-KRB5") def test_SHA(self): assert_equal_openssl("SHA", "SHA:-SSLv2:-DH:-KRB5:-PSK:-IDEA:-SEED") def test_HIGH(self): assert_equal_openssl("HIGH", "HIGH:-SSLv2:-DH:-ADH:-KRB5:-PSK") def test_MEDIUM(self): assert_equal_openssl("MEDIUM", "MEDIUM:-SSLv2:-ADH:-KRB5:-PSK:-SEED:-IDEA") def test_LOW(self): assert_equal_openssl("LOW", "LOW:-SSLv2:-DH:-ADH:-KRB5") def test_SHA256(self): assert_equal_openssl("SHA256", "SHA256:-ADH:-DSS:-DH") def test_SHA_MD5_minus_AES(self): assert_equal_openssl("SHA:MD5:-AES", "SHA:MD5:-AES:-SSLv2:-DH:-DSS:-KRB5:-SEED:-PSK:-IDEA") def test_SHA_MD5_not_AES(self): assert_equal_openssl("!AES:SHA:MD5", "!AES:SHA:MD5:-SSLv2:-DH:-KRB5:-DSS:-SEED:-PSK:-IDEA") def test_aECDH(self): assert_equal_openssl("aECDH", "aECDH") def test_kECDH(self): assert_equal_openssl("kECDH", "kECDH") def test_kECDHe(self): assert_equal_openssl("kECDHe", "kECDHe") def test_kECDHr(self): assert_equal_openssl("kECDHr", "kECDHr") def test_kEECDH(self): assert_equal_openssl("kEECDH", "kEECDH") def test_AECDH(self): assert_equal_openssl("AECDH", "AECDH") def test_EECDH(self): assert_equal_openssl("EECDH", "EECDH") def test_ECDSA(self): assert_equal_openssl("ECDSA", "ECDSA") def test_aECDSA(self): assert_equal_openssl("aECDSA", "aECDSA") def test_AESGCM(self): assert_equal_openssl("AESGCM", "AESGCM:-DH") def test_ECDH(self): assert_equal_openssl("ECDH", "ECDH") def test_AES_no_ECDH(self): assert_equal_openssl("AES:-ECDH", "AES:-ECDH:-ADH:-PSK:-DH") assert_equal_openssl("AES+RSA", "AES+RSA") def test_logical_and_3DES_RSA(self): assert_equal_openssl("3DES+RSA", "3DES+RSA:-SSLv2") def test_logical_and_RSA_RC4(self): assert_equal_openssl("RSA+RC4", "RSA+RC4:-SSLv2") def test_logical_and_ECDH_SHA(self): assert_equal_openssl("ECDH+SHA", "ECDH+SHA") def test_logical_and_RSA_RC4_no_SHA(self): assert_equal_openssl("RSA+RC4:!SHA", "RSA+RC4:-SSLv2:!SHA") def test_additive_RSA_RC4(self): assert_equal_openssl("RSA:+RC4", "RSA:+RC4:-SSLv2:-SEED:-IDEA") def test_negative_plus_RSA_MD5(self): assert_equal_openssl("-RC2:RSA+MD5", "-RC2:RSA+MD5:-SSLv2") def test_DEFAULT_aRSA(self): assert_no_NULL("DEFAULT:aRSA") def test_nss_subtraction(self): (out, err, rc) = run([exe, "+rsa_rc4_128_md5,+rsa_rc4_128_sha,-rsa_rc4_128_md5"]) assert rc == 0 assert_equal(out, 'rsa_rc4_128_sha') def test_openssl_cipher(self): (out, err, rc) = run([exe, "DES-CBC3-SHA"]) assert rc == 0 assert_equal(out, 'rsa_3des_sha') def test_openssl_cipherlist(self): (out, err, rc) = run([exe, "DES-CBC3-SHA:RC4-SHA"]) assert rc == 0 assert_equal(out, 'rsa_rc4_128_sha, rsa_3des_sha') # As long as at least one is valid, things are ok def test_nss_unknown(self): (out, err, rc) = run([exe, "+rsa_rc4_128_md5,+unknown"]) assert rc == 0 assert_equal(out, 'rsa_rc4_128_md5') def test_nss_single(self): (out, err, rc) = run([exe, "+aes_128_sha_256"]) assert rc == 0 assert_equal(out, 'aes_128_sha_256') def test_openssl_single_cipher(self): assert_equal_openssl("RC4-SHA", "RC4-SHA") def test_invalid_format(self): (out, err, rc) = run([exe, "none"]) assert rc == 1 mod_nss-1.0.12/test/test_config.py000066400000000000000000000156771260357105600171170ustar00rootroot00000000000000# Copyright (C) 2013 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import os import re import ssl import time import string import requests import socket import subprocess import test_util import test_request # Utility functions to assist in creating Apache configuration based # on test suite DEF_PORT=8000 FQDN = socket.gethostname() default_vars = dict( DBPREFIX = '', SERVER_PORT = DEF_PORT, SERVER_NAME = FQDN, TEST_ROOT = '%s/work/httpd' % os.getcwd(), SERVER_ROOT = '%s/work/httpd' % os.getcwd(), ) def template_str(txt, vars): val = string.Template(txt).substitute(vars) # eval() is a special string one can insert into a template to have the # Python interpreter evaluate the string. This is intended to allow # math to be performed in templates. pattern = re.compile('(eval\s*\(([^()]*)\))') val = pattern.sub(lambda x: str(eval(x.group(2))), val) return val def template_file(infilename, vars): """Read a file and perform template substitutions""" with open(infilename) as f: return template_str(f.read(), vars) def write_template_file(infilename, outfilename, vars): """Read a file and perform template substitutions""" replacevars = dict(default_vars.items() + vars.items()) with open(outfilename, 'w') as f: f.write('%s\n' % template_file(infilename, replacevars)) def stop_apache(): """Stop the Apache process""" cwd = os.getcwd() # no try/except, just let it fail os.chdir('work/httpd') p = subprocess.Popen(['./stop'], close_fds=True) def restart_apache(): """Restart the Apache process""" cwd = os.getcwd() # no try/except, just let it fail os.chdir('work/httpd') p = subprocess.Popen(['./stop'], close_fds=True) time.sleep(5) p = subprocess.Popen(['./start'], close_fds=True) os.chdir(cwd) test_util.wait_for_open_ports(FQDN, DEF_PORT) EXPECTED = """Expected %r to raise %s. options = %r output = %r""" UNEXPECTED = """Expected %r to raise %s, but caught different. options = %r %s: %s""" class Declarative(object): """A declarative-style test suite A Declarative test suite is controlled by the ``tests`` class variable. The ``tests`` is a list of dictionaries with the following keys: ``desc`` A name/description of the test ``request`` A (uri, options) triple specifying the uri to run ``expected`` Can be either an ``errors.PublicError`` instance, in which case the command must fail with the given error; or the expected result. The result is checked with ``tests.util.assert_deepequal``. """ tests = tuple() def test_generator(self): """ Iterate through tests. nose reports each one as a separate test. """ # Iterate through the tests: name = self.__class__.__name__ for (i, test) in enumerate(self.tests): nice = '%s[%d]: %s: %s' % ( name, i, test['request'][0], test.get('desc', '') ) func = lambda: self.check(nice, **test) func.description = nice yield (func,) def make_request(self, uri, options): session = requests.Session() session.mount('https://', test_request.MyAdapter()) verify = dict(verify = options) port = options.get('port', DEF_PORT) host = options.get('host', FQDN) request = session.get('https://%s:%d%s' % (host, port, uri), **verify) return request def check(self, nice, desc, request, expected, cipher=None, protocol=None, expected_str=None, content=None): # TODO: need way to set auth, etc. (uri, options) = request if not 'verify' in options: options['verify'] = 'work/httpd/alias/ca.pem' if isinstance(expected, Exception): self.check_exception(nice, uri, options, expected, expected_str) else: self.check_result(nice, uri, options, expected, cipher, protocol, content) def check_exception(self, nice, uri, options, expected, expected_str): """ With some requests we expect an exception to be raised. See if is the one we expect. There is at least one case where depending on the distro either a CertificateError or an SSLError is thrown but the message of the exception is the same, so compare that. """ klass = expected.__class__ name = klass.__name__ try: output = self.make_request(uri, options) except StandardError, e: pass else: raise AssertionError( EXPECTED % (uri, name, options, output) ) if not isinstance(e, klass): if expected_str not in str(e): raise AssertionError( UNEXPECTED % (uri, name, options, e.__class__.__name__, e) ) def check_result(self, nice, uri, options, expected, cipher=None, protocol=None, content=None): name = expected.__class__.__name__ request = self.make_request(uri, options) has_sni = options.get('sni', False) if content and not content in request.content: raise AssertionError( 'Expected %s not in %s' % (content, request.content) ) if cipher: if has_sni: raise AssertionError('Cannot do cipher tests in SNI') client_cipher = request.raw._pool._get_conn().client_cipher if cipher != client_cipher[0]: raise AssertionError( 'Expected cipher %s, got %s' % (cipher, client_cipher[0]) ) if protocol: client_cipher = request.raw._pool._get_conn().client_cipher if has_sni: raise AssertionError('Cannot do protocol tests in SNI') if protocol != client_cipher[1]: raise AssertionError( 'Expected protocol %s, got %s' % (protocol, client_cipher[1]) ) if expected != request.status_code: raise AssertionError( 'Expected status %s, got %s' % (expected, request.status_code) ) mod_nss-1.0.12/test/test_request.py000066400000000000000000000173441260357105600173330ustar00rootroot00000000000000# # Override a slew of methods to have more control over SSL import socket import requests import urlparse import logging import socket from requests.packages.urllib3.util import get_host from requests.packages.urllib3.util.timeout import Timeout from requests.packages.urllib3.contrib import pyopenssl from requests.packages.urllib3.connectionpool import HTTPConnectionPool, HTTPSConnectionPool, VerifiedHTTPSConnection # Don't bend over backwards for ssl support, assume it is there. import ssl try: # Python 3 from http.client import HTTPConnection, HTTPException from http.client import HTTP_PORT, HTTPS_PORT from http.client import HTTPSConnection except ImportError: from httplib import HTTPConnection, HTTPException from httplib import HTTP_PORT, HTTPS_PORT from httplib import HTTPSConnection try: # python3.2+ from ssl import match_hostname, CertificateError except ImportError: try: # Older python where the backport from pypi is installed from backports.ssl_match_hostname import match_hostname, CertificateError except ImportError: # Other older python we use the urllib3 bundled copy from urllib3.packages.ssl_match_hostname import match_hostname, CertificateError SAVE_DEFAULT_SSL_CIPHER_LIST = pyopenssl.DEFAULT_SSL_CIPHER_LIST log = logging.getLogger(__name__) def connection_from_url(url, **kw): """ Given a url, return an :class:`.ConnectionPool` instance of its host. This is a shortcut for not having to parse out the scheme, host, and port of the url before creating an :class:`.ConnectionPool` instance. :param url: Absolute URL string that must include the scheme. Port is optional. :param \**kw: Passes additional parameters to the constructor of the appropriate :class:`.ConnectionPool`. Useful for specifying things like timeout, maxsize, headers, etc. Example: :: >>> conn = connection_from_url('http://google.com/') >>> r = conn.request('GET', '/') """ scheme, host, port = get_host(url) if scheme == 'https': return MyHTTPSConnectionPool(host, port=port, **kw) else: return HTTPConnectionPool(host, port=port, **kw) class MyHTTPSConnectionPool(HTTPSConnectionPool): def __init__(self, host, port=None, strict=False, timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, block=False, headers=None, key_file=None, cert_file=None, cert_reqs='CERT_REQUIRED', ca_certs='/etc/ssl/certs/ca-certificates.crt', ssl_version=ssl.PROTOCOL_SSLv23, ciphers=None): super(HTTPSConnectionPool, self).__init__(host, port, strict, timeout, maxsize, block, headers) self.key_file = key_file self.cert_file = cert_file self.cert_reqs = cert_reqs self.ca_certs = ca_certs self.ssl_version = ssl_version self.ciphers = ciphers self.assert_hostname = None self.assert_fingerprint = None def _new_conn(self): """ Return a fresh :class:`httplib.HTTPSConnection`. """ self.num_connections += 1 log.info("Starting new HTTPS connection (%d): %s" % (self.num_connections, self.host)) #if not ssl: # Platform-specific: Python compiled without +ssl # if not HTTPSConnection or HTTPSConnection is object: # raise SSLError("Can't connect to HTTPS URL because the SSL " # "module is not available.") # return HTTPSConnection(host=self.host, port=self.port) connection = MyVerifiedHTTPSConnection(host=self.host, port=self.port) connection.sni = self.sni connection.set_cert(key_file=self.key_file, cert_file=self.cert_file, cert_reqs=self.cert_reqs, ca_certs=self.ca_certs) connection.set_ssl_version(self.ssl_version) connection.set_ciphers(self.ciphers) return connection class MyVerifiedHTTPSConnection(VerifiedHTTPSConnection): """ Based on httplib.HTTPSConnection but wraps the socket with SSL certification. """ cert_reqs = None ca_certs = None client_cipher = None is_verified = True # squelch warning sni = False assert_hostname = None assert_fingerprint = None def set_cert(self, key_file=None, cert_file=None, cert_reqs='CERT_NONE', ca_certs=None): ssl_req_scheme = { 'CERT_NONE': ssl.CERT_NONE, 'CERT_OPTIONAL': ssl.CERT_OPTIONAL, 'CERT_REQUIRED': ssl.CERT_REQUIRED } self.key_file = key_file self.cert_file = cert_file self.cert_reqs = ssl_req_scheme.get(cert_reqs) or ssl.CERT_NONE self.ca_certs = ca_certs def set_ssl_version(self, ssl_version=ssl.PROTOCOL_SSLv23): self.ssl_version = ssl_version def set_ciphers(self, ciphers=None): self.ciphers = ciphers def connect(self): if self.sni: if self.ciphers: pyopenssl.DEFAULT_SSL_CIPHER_LIST = self.ciphers else: pyopenssl.DEFAULT_SSL_CIPHER_LIST = SAVE_DEFAULT_SSL_CIPHER_LIST return super(MyVerifiedHTTPSConnection, self).connect() # Add certificate verification sock = socket.create_connection((self.host, self.port), self.timeout) # Wrap socket using verification with the root certs in # trusted_root_certs self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, cert_reqs=self.cert_reqs, ca_certs=self.ca_certs, ssl_version=self.ssl_version, ciphers=self.ciphers) if self.ca_certs: match_hostname(self.sock.getpeercert(), self.host) def close(self): if not self.sni: if self.sock: self.client_cipher = self.sock.cipher() super(MyVerifiedHTTPSConnection, self).close() class MyAdapter(requests.adapters.HTTPAdapter): def get_connection(self, url, proxies=None): """Returns a connection for the given URL.""" # proxies are not supported return connection_from_url(url) def cert_verify(self, conn, url, verify, cert): # I'm overloading the content of verify since this API is so # braindead. If verify is a dict then key 'verify' represents the # original meaning, the other keys are my own. if isinstance(verify, bool): super(MyAdapter, self).cert_verify(conn, url, verify, cert) elif isinstance(verify, dict): if 'verify' in verify: super(MyAdapter, self).cert_verify(conn, url, verify['verify'], cert) if 'ssl_version' in verify: conn.ssl_version = verify['ssl_version'] if 'ciphers' in verify: conn.ciphers = verify['ciphers'] if 'cert_file' in verify: conn.cert_file = verify['cert_file'] if 'key_file' in verify: conn.key_file = verify['key_file'] conn.sni = verify.get('sni', False) else: # huh? Do nothing pass """ s = requests.Session() s.mount('https://', MyAdapter()) try: r = s.get('https://test.example.com:8000/', verify={'verify': False, 'ssl_version': ssl.PROTOCOL_SSLv23, 'ciphers': 'HIGH'}) cipher = r.raw._pool._get_conn().client_cipher except requests.exceptions.SSLError, e: print e.message else: print r.status_code print cipher #request = requests.get('https://test.example.com:8000/', verify=False) #print request.status_code """ mod_nss-1.0.12/test/test_util.py000066400000000000000000000044351260357105600166150ustar00rootroot00000000000000import socket import time import subprocess def host_port_open(host, port, socket_type=socket.SOCK_STREAM, socket_timeout=None): for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket_type): af, socktype, proto, canonname, sa = res try: try: s = socket.socket(af, socktype, proto) except socket.error: s = None continue if socket_timeout is not None: s.settimeout(socket_timeout) s.connect(sa) if socket_type == socket.SOCK_DGRAM: s.send('') s.recv(512) return True except socket.error, e: pass finally: if s: s.close() return False def wait_for_open_ports(host, ports, timeout=0): """ Wait until the specified port(s) on the remote host are open. Timeout in seconds may be specified to limit the wait. If the timeout is exceeded, socket.timeout exception is raised. """ if not isinstance(ports, (tuple, list)): ports = [ports] op_timeout = time.time() + timeout for port in ports: while True: port_open = host_port_open(host, port) if port_open: break if timeout and time.time() > op_timeout: # timeout exceeded raise socket.timeout() time.sleep(1) def shell_quote(string): return "'" + string.replace("'", "'\\''") + "'" def run(args): """ Execute a command and return stdin, stdout and the process return code. :param args: List of arguments for the command """ p_in = None p_out = None p_out = subprocess.PIPE p_err = subprocess.PIPE arg_string = ' '.join(shell_quote(a) for a in args) try: p = subprocess.Popen(args, stdout=p_out, stderr=p_err, close_fds=True) stdout,stderr = p.communicate(None) except KeyboardInterrupt: p.wait() raise return (stdout, stderr, p.returncode) def assert_equal(got, expected): if got.strip() != expected.strip(): raise AssertionError( "assert_deepequal: expected != got. " \ "expected = %r got = %r" % (expected, got) ) mod_nss-1.0.12/test/testsni.py000066400000000000000000000060701260357105600162670ustar00rootroot00000000000000from test_config import Declarative, write_template_file, restart_apache from test_config import stop_apache import ssl import requests.exceptions import os class test_suite1(Declarative): @classmethod def setUpClass(cls): write_template_file('suite1.tmpl', 'work/httpd/conf/test.conf', {'DBPREFIX': os.environ.get('DBPREFIX', ''), 'SNI': 'on', 'PRESERVEHOST': 'Off', } ) for i in range(1,26): write_template_file('sni.tmpl', 'work/httpd/conf.d/sni%d.conf' % i, {'DBPREFIX': os.environ.get('DBPREFIX', ''), 'SNINAME': 'www%d.example.com' % i, 'SNINUM': i, } ) restart_apache() @classmethod def tearDownClass(cls): stop_apache() tests = [ dict( desc='Get this host', request=('/', {'sni': True}), expected=200, content='content', ), dict( desc='Get www1.example.com', request=('/', {'host': 'www1.example.com', 'sni': True}), expected=200, content='sni1', ), dict( desc='Get www2.example.com', request=('/', {'host': 'www2.example.com', 'sni': True}), expected=200, content='sni2', ), dict( desc='Get www4.example.com', request=('/', {'host': 'www4.example.com', 'sni': True}), expected=200, content='sni4', ), dict( desc='Get www6.example.com', request=('/', {'host': 'www6.example.com', 'sni': True}), expected=200, content='sni6', ), dict( desc='Get www1.example.com again', request=('/', {'host': 'www1.example.com', 'sni': True}), expected=200, content='sni1', ), dict( desc='Get non-existant page on www8.example.com', request=('/notfound', {'host': 'www8.example.com', 'sni': True}), expected=404, ), dict( desc='Client auth to www10.example.com, valid certificate', request=('/acl/aclS01.html', { 'host': 'www10.example.com', 'sni': True, 'key_file': 'work/httpd/alpha.key', 'cert_file': 'work/httpd/alpha.crt',} ), expected=200, content='sni10', ), dict( desc='Get www25.example.com', request=('/', {'host': 'www25.example.com', 'sni': True}), expected=200, content='sni25', ), dict( desc='Non-existant www26.example.com', request=('/', {'host': 'www26.example.com', 'sni': True}), expected=requests.exceptions.ConnectionError(), ), dict( desc='Reverse proxy request when SNI is enabled', request=('/proxy/index.html', {'sni': True}), expected=200, ), ] mod_nss-1.0.12/test_cipher.c000066400000000000000000000062161260357105600157240ustar00rootroot00000000000000/* Copyright 2001-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include "ap_release.h" /* Fake a few Apache and NSPR data types and definitions */ typedef char server_rec; typedef int PRBool; typedef int PRInt32; #define PR_FALSE 0 #define PR_TRUE 1 #include extern cipher_properties ciphers_def[]; extern ciphernum; /* An Apache-like error logger */ #if AP_SERVER_MINORVERSION_NUMBER <= 2 int ap_log_error(const char *fn, int line, #else int ap_log_error_(const char *fn, int line, int module_index, #endif int level, int status, const server_rec *s, char *fmt, ...) { char out[1024]; va_list args; va_start(args, fmt); vsprintf(out, fmt, args); fprintf(stderr,"%s:%d, %s\n", fn, line, out); va_end(args); return 0; } #if AP_SERVER_MINORVERSION_NUMBER > 2 #define ap_log_error_ ap_log_error #endif int main(int argc, char ** argv) { int rv=0; int i; char *ciphers; PRBool openssl_output = PR_FALSE; PRBool ciphers_list[ciphernum]; if (argc != 2 && argc != 3) { fprintf(stderr, "Usage: test_cipher [--count] [--o] \n"); exit(1); } if (!strcmp(argv[1], "--count")) { fprintf(stdout, "%d\n", ciphernum); exit(0); } for (i=0; i