EasyRSA-3.1.7/000775 000765 000024 00000000000 14512342147 013432 5ustar00ecriststaff000000 000000 EasyRSA-3.1.7/openssl-easyrsa.cnf000664 000765 000024 00000012031 14512342147 017247 0ustar00ecriststaff000000 000000 # For use with Easy-RSA 3.0+ and OpenSSL or LibreSSL #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = $ENV::EASYRSA_PKI # Where everything is kept certs = $dir # Where the issued certs are kept crl_dir = $dir # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/certs_by_serial # default place for new certs. certificate = $dir/ca.crt # The CA certificate serial = $dir/serial # The current serial number crl = $dir/crl.pem # The current CRL private_key = $dir/private/ca.key # The private key RANDFILE = $dir/.rand # private random number file x509_extensions = basic_exts # The extensions to add to the cert # A placeholder to handle the --copy-ext feature: #%COPY_EXTS% # Do NOT remove or change this line as --copy-ext support requires it # This allows a V2 CRL. Ancient browsers don't like it, but anything Easy-RSA # is designed for will. In return, we get the Issuer attached to CRLs. crl_extensions = crl_ext default_days = $ENV::EASYRSA_CERT_EXPIRE # how long to certify for default_crl_days = $ENV::EASYRSA_CRL_DAYS # how long before next CRL default_md = $ENV::EASYRSA_DIGEST # use public key default MD # Note: preserve=no|yes, does nothing for EasyRSA. # Use sign-req command option 'preserve' instead. preserve = no # keep passed DN ordering # This allows to renew certificates which have not been revoked unique_subject = no # A few different ways of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_anything # For the 'anything' policy, which defines allowed DN fields [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional serialNumber = optional #################################################################### # Easy-RSA request handling # We key off $DN_MODE to determine how to format the DN [ req ] default_bits = $ENV::EASYRSA_KEY_SIZE default_keyfile = privkey.pem default_md = $ENV::EASYRSA_DIGEST distinguished_name = $ENV::EASYRSA_DN x509_extensions = easyrsa_ca # The extensions to add to the self signed cert # A placeholder to handle the $EXTRA_EXTS feature: #%EXTRA_EXTS% # Do NOT remove or change this line as $EXTRA_EXTS support requires it #################################################################### # Easy-RSA DN (Subject) handling # Easy-RSA DN for cn_only support: [ cn_only ] commonName = Common Name (eg: your user, host, or server name) commonName_max = 64 commonName_default = $ENV::EASYRSA_REQ_CN # Easy-RSA DN for org support: [ org ] countryName = Country Name (2 letter code) countryName_default = $ENV::EASYRSA_REQ_COUNTRY countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = $ENV::EASYRSA_REQ_PROVINCE localityName = Locality Name (eg, city) localityName_default = $ENV::EASYRSA_REQ_CITY 0.organizationName = Organization Name (eg, company) 0.organizationName_default = $ENV::EASYRSA_REQ_ORG organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = $ENV::EASYRSA_REQ_OU commonName = Common Name (eg: your user, host, or server name) commonName_max = 64 commonName_default = $ENV::EASYRSA_REQ_CN emailAddress = Email Address emailAddress_default = $ENV::EASYRSA_REQ_EMAIL emailAddress_max = 64 serialNumber = Serial-number (eg, device serial-number) serialNumber_default = $ENV::EASYRSA_REQ_SERIAL #################################################################### # Easy-RSA cert extension handling # This section is effectively unused as the main script sets extensions # dynamically. This core section is left to support the odd usecase where # a user calls openssl directly. [ basic_exts ] basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always # The Easy-RSA CA extensions [ easyrsa_ca ] # PKIX recommendations: subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always # This could be marked critical, but it's nice to support reading by any # broken clients who attempt to do so. basicConstraints = CA:true # Limit key usage to CA tasks. If you really want to use the generated pair as # a self-signed cert, comment this out. keyUsage = cRLSign, keyCertSign # nsCertType omitted by default. Let's try to let the deprecated stuff die. # nsCertType = sslCA # A placeholder to handle the $X509_TYPES and CA extra extensions $EXTRA_EXTS: #%CA_X509_TYPES_EXTRA_EXTS% # Do NOT remove or change this line as $X509_TYPES and EXTRA_EXTS demands it # CRL extensions. [ crl_ext ] # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always,issuer:always EasyRSA-3.1.7/gpl-2.0.txt000664 000765 000024 00000043254 14512342147 015262 0ustar00ecriststaff000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. EasyRSA-3.1.7/ChangeLog000664 000765 000024 00000026246 14512342147 015216 0ustar00ecriststaff000000 000000 Easy-RSA 3 ChangeLog 3.2.0 (TBD) 3.1.7 (2023-10-13) * Rewrite vars-auto-detect, adhere to EasyRSA-Advanced.md (#1029) Under the hood, this is a considerable change but there are no user noticable differences. With the exception of: Caveat: The default '$PWD/pki/vars' file is forbidden to change either EASYRSA or EASYRSA_PKI, which are both implied by default. * EasyRSA-Advanced.md: Correct vars-auto-detect hierarchy (#1029) Commit: ecd65065e3303da78811278a154ef7a969c2777b EASYRSA/vars is moved to a higher priority than a default PKI. vars-auto-detect no longer searches 'easyrsa' program directory. * gen-crl: preserve existing crl.pem ownership+mode (#1020) * New command: make-vars - Print vars.example (here-doc) to stdout (#1024) * show-expire: Calculate cert. expire seconds from DB date (#1023) * Update OpenSSL to 3.1.2 3.1.6 (2023-07-18) * New commands: 'inline' and 'x509-eku' (#993) inline: Build an inline file for a commonName x509-eku: Extract X509v3 extended key usage from a certificate * Expose serial-check, display-dn, display-san and default-san to command line. (#980) (Debugging functions, which remain undocumented) * Expand default status to include vars-file and CA status (#973) * sign-req: Allow the CSR DN-field order to be preserved (#970) 3.1.5 (2023-06-10) * Build Update: script now supports signing and verifying * Automate support-file creation (Free packaging) (#964) * build-ca: New command option 'raw-ca', abbrevation: 'raw' (#963) This 'raw' method, is the most reliable way to build a CA, with a password, without writing the CA password to a temp-file. This option completely replaces both methods below: * build-ca: New option --ca-via-stdin, use SSL -pass* argument 'stdin' (#959) Option '--ca-via-stdin' offers no more security than standard method. Easy-RSA version 3.1.4 ONLY. * build-ca: Replace password temp-files with file-descriptors (#955) Using file-descriptors does not work in Windows. Easy-RSA version 3.1.3 ONLY. 3.1.4 (2023-05-23) * build-ca: New option --ca-via-stdin, use SSL -pass* argument 'stdin' (#959) * build-ca: Revert manual CA password method to temp-files (#959) Supersedes #955 Release v3.1.3 was fatally flawed, it would fail to build a CA under Windows. Release v3.1.4 is specifically a bugfix ONLY, to resolve the Windows problem. See the following commits for further details: 5d7ad1306d5ebf1588aef77eb3445e70cf5b4ebc build-ca: Revert manual CA password method to temp-files c11135d19b2e7e7385d28abb1132978c849dfa74 build-ca: Use OpenSSL password I/O argument 'stdin' 27870d695a324e278854146afdac5d6bdade9bba build-ca: Replace password temp-file method with file-descriptors Superseded by 5d7ad13 above. 3.1.3 (2023-05-19) * build-ca: Replace password temp-files with file-descriptors (#955) Superseded by #959 * Replace --fix-offset with --startdate, --enddate (#918) * Introduce option -S|--silent-ssl: Silence SSL output (#913) * Only create a random serial number file when expected (#896) * Always verify SSL lib, for all commands (#877) * Option --fix-offset: Adjust off-by-one day (#847) Superseded (#918) * Update OpenSSL to v3.0.8 3.1.2 (2023-01-13) * build-full: Always enable inline file creation (#834) * Make default Edwards curve ED25519 (#828) * Allow --fix-offset to create post-dated certificates (#804) Superseded (#918) * Introduce command 'set-pass' (#756) * Introduce global option '--nopass|--no-pass' (#752) * Introduce global option '--notext|--no-text' (#745) * Command 'help': For unknown command, exit with error (#737) * Find data-files in the correct order (#727 - Reported #725) * Update OpenSSL to 3.0.7 for Windows distribution 3.1.1 (2022-10-13) * Remove command 'renewable' (#715) * Expand 'show-renew', include 'renewed/certs_by_serial' (#700) * Resolve long-standing issue with --subca-len=N (#691) * ++ NOTICE: Add EasyRSA-Renew-and-Revoke.md (#690) * Require 'openssl-easyrsa.cnf' is up to date (#695} * Introduce 'renew' (version 3). Only renew cert (#688) * Always ensure X509-types files exist (#581 #696) * Expand alias '--days' to all suitable options with a period (#674) * Introduce --keep-tmp, keep temp files for debugging (#667) * Add serialNumber (OID 2.5.4.5) to DN 'org' mode (#606) * Support ampersand and dollar-sign in vars file (#590) * Introduce 'rewind-renew' (#579) * Expand status reports to include checking a single cert (#577) * Introduce 'revoke-renewed' (#547) * update OpenSSL for Windows to 3.0.5 3.1.0 (2022-05-18) * Introduce basic support for OpenSSL version 3 (#492) * Update regex in grep to be POSIX compliant (#556) * Introduce status reporting tools (#555 & #557) * Display certificates using UTF8 (#551) * Allow certificates to be created with fixed date offset (#550) * Add 'verify' to verify certificate against CA (#549) * Add PKCS#12 alias 'friendlyName' (#544) * Support multiple IP-Addresses in SAN (#564) * Add option '--renew-days=NN', custom renew grace period (#557) * Add 'nopass' option to the 'export-pkcs' functions (#411) * Add support for 'busybox' (#543) * Add option '--tmp-dir=DIR' to declare Temp-dir (Commit f503a22) 3.0.9 (2022-05-17) * Upgrade OpenSSL from 1.1.0j to 1.1.1o (#405, #407) - We are buliding this ourselves now. * Fix --version so it uses EASYRSA_OPENSSL (#416) * Use openssl rand instead of non-POSIX mktemp (#478) * Fix paths with spaces (#443) * Correct OpenSSL version from Homebrew on macOs (#416) * Fix revoking a renewed certificate (Original PR #394) Follow-up commit: ef22701878bb10df567d60f2ac50dce52a82c9ee * Introduce 'show-crl' (d1993892178c5219f4a38d50db3b53d1a972b36c) * Support Windows-Git 'version of bash' (#533) * Disallow use of single quote (') in vars file, Warning (#530) * Creating a CA uses x509-types/ca and COMMON (#526) * Prefer 'PKI/vars' over all other locations (#528) * Introduce 'init-pki soft' option (#197) * Warnings are no longer silenced by --batch (#523) * Improve packaging options (#510) * Update regex for POSIX compliance (#556) * Correct date format for Darwin/BSD (#559) 3.0.8 (2020-09-09) * Provide --version option (#372) * Version information now within generated certificates like on *nix * Fixed issue where gen-dh overwrote existing files without warning (#373) * Fixed issue with ED/EC certificates were still signed by RSA (#374) * Added support for export-p8 (#339) * Clarified error message (#384) * 2->3 upgrade now errors and prints message when vars isn't found (#377) 3.0.7 (2020-03-30) * Include OpenSSL libs and binary for Windows 1.1.0j * Remove RANDFILE environment variable (#261) * Workaround for bug in win32 mktemp (#247, #305, PR #312) * Handle IP address in SAN and renewals (#317) * Workaround for ash and no set -o echo (#319) * Shore up windows testing framework (#314) * Provide upgrade mechanism for older versions of EasyRSA (#349) * Add support for KDC certificates (#322) * Add support for Edward Curves (#354, #350) * Add support for EASYRSA_PASSIN and EASYRSA_PASSOUT env vars (#368) * Add support for RID to SAN (#362) 3.0.6 (2019-02-01) * Certificates that are revoked now move to a revoked subdirectory (#63) * EasyRSA no longer clobbers non-EASYRSA environment variables (#277) * More sane string checking, allowing for commas in CN (#267) * Support for reasonCode in CRL (#280) * Better handling for capturing passphrases (#230, others) * Improved LibreSSL/MacOS support * Adds support to renew certificates up to 30 days before expiration (#286) - This changes previous behavior allowing for certificate creation using duplicate CNs. 3.0.5 (2018-09-15) * Fix #17 & #58: use AES256 for CA key * Also, don't use read -s, use stty -echo * Fix broken "nopass" option * Add -r to read to stop errors reported by shellcheck (and to behave) * Remove overzealous quotes around $pkcs_opts (more SC errors) * Support for LibreSSL * EasyRSA version will be reported in certificate comments * Client certificates now expire in 3 year (1080 days) by default 3.0.4 (2018-01-21) * Remove use of egrep (#154) * Integrate with Travis-CI (#165) * Remove "local" from variable assignment (#165) * Other changes related to Travis-CI fixes * Assign values to variables defined previously w/local * Finally(?) fix the subjectAltName issues I presented earlier (really fixes #168) 3.0.3 (2017-08-22) * Include mktemp windows binary * copy CSR extensions into signed certificate 3.0.2 (2017-08-21) * Add missing windows binaries 3.0.1 (2015-10-25) * Correct some packaging errors 3.0.0 (2015-09-07) * cab4a07 Fix typo: Hellman (ljani: Github) * 171834d Fix typo: Default (allo-: Github) * 8b42eea Make aes256 default, replacing 3des (keros: Github) * f2f4ac8 Make -utf8 default (roubert: Github) 3.0.0-rc2 (2014/07/27) * 1551e5f docs: fix typo (Josh Cepek ) * 7ae44b3 Add KNOWN_ISSUES to stage next -rc release (Josh Cepek ) * a0d58b2 Update documentation (Josh Cepek ) * 5758825 Fix vars.example with proper path to extensions.temp (Josh Cepek ) * 89f369c Add support to change private key passphrases (Josh Cepek ) * 49d7c10 Improve docs: add Upgrade-Notes; add online support refs (Josh Cepek ) * fcc4547 Add build-dist packaging script; update Building docs (Josh Cepek ) * f74d08e docs: update Hacking.md with layout & git conventions (Josh Cepek ) * 0754f23 Offload temp file removal to a clean_temp() function (Josh Cepek ) * 1c90df9 Fix incorrect handling of invalid --use-algo option (Josh Cepek ) * c86289b Fix batch-mode handling with changes in e75ad75 (Josh Cepek ) * e75ad75 refine how booleans are evaluated (Eric F Crist ) * cc19823 Merge PKCS#7 feature from pull req #14 (Author: Luiz Angelo Daros de Luca ) (Modified-By: Josh Cepek ) * 8b1fe01 Support OpenSSL-0.9.8 with the EXTRA_EXTS feature (Josh Cepek ) * d5516d5 Windows: make builds easier by using a matching dir structure (Josh Cepek ) * dc2e6dc Windows: improve external checks and env-var help (Josh Cepek ) 3.0.0-rc1 (2013/12/01) * The 3.x release is a nearly complete re-write of the 2.x codebase * Initial 3.x series code by Josh Cepek -- continuing maintenance by the OpenVPN community development team and associated contributors * Add ECDSA (elliptic curve) support, thanks to Steffan Karger EasyRSA-3.1.7/x509-types/000775 000765 000024 00000000000 14512342147 015301 5ustar00ecriststaff000000 000000 EasyRSA-3.1.7/README.md000664 000765 000024 00000004345 14512342147 014717 0ustar00ecriststaff000000 000000 [![CI](https://github.com/Openvpn/easy-rsa/actions/workflows/action.yml/badge.svg)](https://github.com/Openvpn/easy-rsa/actions/workflows/action.yml) # Overview easy-rsa is a CLI utility to build and manage a PKI CA. In laymen's terms, this means to create a root certificate authority, and request and sign certificates, including intermediate CAs and certificate revocation lists (CRL). # Downloads If you are looking for release downloads, please see the releases section on GitHub. Releases are also available as source checkouts using named tags. # Documentation For 3.x project documentation and usage, see the [README.quickstart.md](README.quickstart.md) file or the more detailed docs under the [doc/](doc/) directory. The .md files are in Markdown format and can be converted to html files as desired for release packages, or read as-is in plaintext. # Getting help using easy-rsa Currently, Easy-RSA development co-exists with OpenVPN even though they are separate projects. The following resources are good places as of this writing to seek help using Easy-RSA: The [openvpn-users mailing list](https://lists.sourceforge.net/lists/listinfo/openvpn-users) is a good place to post usage or help questions. You can also try libera.chat IRC network, in channels #openvpn for general support or #easyrsa for development discussion. # Branch structure The easy-rsa master branch is currently tracking development for the 3.x release cycle. Please note that, at any given time, master may be broken. Feel free to create issues against master, but have patience when using the master branch. It is recommended to use a release, and priority will be given to bugs identified in the most recent release. The prior 2.x and 1.x versions are available as release branches for tracking and possible back-porting of relevant fixes. Branch layout is: master <- 3.1, at present v3.x.x pre-release branches, used for staging branches release/3.0 v3.0.x bugfix/security/openssl updates release/2.x release/1.x LICENSING info for 3.x is in the [COPYING.md](COPYING.md) file # Code style, standards We are attempting to adhere to the POSIX standard, which can be found here: https://pubs.opengroup.org/onlinepubs/9699919799/ EasyRSA-3.1.7/COPYING.md000664 000765 000024 00000002431 14512342147 015064 0ustar00ecriststaff000000 000000 Easy-RSA -- A Shell-based CA Utility ==================================== Copyright (C) 2013 by the Open-Source OpenVPN development community Easy-RSA 3 license: GPLv2 ------------------------- All the Easy-RSA code contained in this project falls under a GPLv2 license with full text available in the Licensing/ directory. Additional components used by this project fall under additional licenses: Additional licenses for external components ------------------------------------------- The following components are under different licenses; while not part of the Easy-RSA source code, these components are used by Easy-RSA or provided in platform distributions as described below: ### OpenSSL OpenSSL is not linked by Easy-RSA, nor is it currently provided in any release package by Easy-RSA. However, Easy-RSA is tightly coupled with OpenSSL, so effective use of this code will require your acceptance and installation of OpenSSL. ### Additional Windows Components The Windows binary package includes mksh/Win32 and unxutils binary components, with full licensing details available in the distro/windows/Licensing/ subdirectory of this project. mksh/Win32 is under a MirOS license (with some additional component licenses present there) and unxutils is under a GPLv2 license. EasyRSA-3.1.7/easyrsa000775 000765 000024 00000561674 14512342147 015052 0ustar00ecriststaff000000 000000 #!/bin/sh # Easy-RSA 3 -- A Shell-based CA Utility # # Copyright (C) 2023 - The Open-Source OpenVPN development community. # A full list of contributors can be found on Github at: # https://github.com/OpenVPN/easy-rsa/graphs/contributors # # This code released under version 2 of the GNU GPL; see COPYING # and the Licensing/ directory of this project for full licensing # details. # Help/usage output to stdout usage() { # command help: print " Easy-RSA 3 usage and overview USAGE: easyrsa [global-options] COMMAND [command-options] To get detailed usage and help for a command, use: ./easyrsa help COMMAND For a list of global-options, use: ./easyrsa help options For a list of extra test commands, use: ./easyrsa help more A list of commands is shown below: init-pki [ cmd-opts ] build-ca [ cmd-opts ] gen-dh gen-req [ cmd-opts ] sign-req [ cmd-opts ] build-client-full [ cmd-opts ] build-server-full [ cmd-opts ] build-serverClient-full [ cmd-opts ] inline revoke [ cmd-opts ] renew revoke-renewed [ cmd-opts ] rewind-renew rebuild [ cmd-opts ] gen-crl update-db show-req [ cmd-opts ] show-cert [ cmd-opts ] show-ca [ cmd-opts ] show-crl show-expire (Optional) show-revoke (Optional) show-renew (Optional) verify-cert import-req export-p1 [ cmd-opts ] export-p7 [ cmd-opts ] export-p8 [ cmd-opts ] export-p12 [ cmd-opts ] set-pass [ cmd-opts ] upgrade " # collect/show dir status: text_only=1 work_dir="${EASYRSA:-undefined}" pki_dir="${EASYRSA_PKI:-undefined}" # CA Status if verify_ca_init test; then CA_cert="$EASYRSA_PKI/ca.crt" CA_status=" CA status: OK" CA_subject="$( OPENSSL_CONF=/dev/null \ "$EASYRSA_OPENSSL" x509 -in "$CA_cert" \ -noout -subject -nameopt multiline )" CA_subject=" CA subject: ${CA_subject#subject=}" CA_status="${CA_status}${NL}${CA_subject}" else CA_status=" CA status: CA has not been built" fi if [ "$invalid_vars" ]; then ivmsg=" *WARNING*: \ Invalid vars setting for EASYRSA and/or EASYRSA_PKI${NL}" else unset -v ivmsg fi # Print details print " DIRECTORY STATUS (commands would take effect on these locations) EASYRSA: $work_dir PKI: $pki_dir vars-file: ${EASYRSA_VARS_FILE:-Missing or undefined}${ivmsg} x509-types: ${EASYRSA_EXT_DIR:-Missing or undefined} $CA_status" # if the vars file in use is not in the PKI # and not user defined then Show the messages prefer_vars_in_pki_msg } # => usage() # Detailed command help # When called with no args, calls usage(), # otherwise shows help for a command # Please maintain strict indentation rules. # Commands are TAB indented, while text is SPACE indented. # 'case' indentation is minimalistic. cmd_help() { unset -v text err_text opts text_only case "$1" in init-pki|clean-all) text=" * init-pki [ cmd-opts ] Removes & re-initializes the PKI directory for a new PKI" opts=" * hard - Recursively delete the PKI directory (default). * soft - Keep the named PKI directory and PKI 'vars' file intact." ;; build-ca) text=" * build-ca [ cmd-opts ] Creates a new CA" opts=" * raw-ca - ONLY use SSL binary to input CA password raw (Equivalent to global option '--raw-ca') * nopass - Do not encrypt the private key (Default: encrypted) (Equivalent to global option '--nopass|--no-pass') * subca - Create an intermediate CA keypair and request intca (default is a root CA)" ;; gen-dh) text=" * gen-dh Generates DH (Diffie-Hellman) parameters file" ;; gen-req) text=" * gen-req [ cmd-opts ] Generate a standalone-private-key and certificate-signing-request This request is suitable for sending to a remote CA for signing." opts=" * nopass - Do not encrypt the private key (Default: encrypted) (Equivalent to global option '--nopass|--no-pass') * text - Include certificate text in request" ;; sign|sign-req) text=" * sign-req [ cmd-opts ] Sign a certificate request of the defined type. must be a known type. eg: 'client', 'server', 'serverClient', 'ca' or a user-added type. All supported types are listed in the x509-types directory. This request file must exist in the reqs/ dir and have a .req file extension. See 'import-req' for importing from other sources." opts=" * preserve - Use the DN-field order of the CSR not the CA." ;; build|build-client-full|build-server-full|build-serverClient-full) text=" * build-client-full [ cmd-opts ] * build-server-full [ cmd-opts ] * build-serverClient-full [ cmd-opts ] Generate a keypair and sign locally. This mode uses the as the X509 commonName." opts=" * nopass - Do not encrypt the private key (Default: encrypted) (Equivalent to global option '--nopass|--no-pass')" ;; inline) text=" * inline Print inline data for , with key and CA. * NOTE: To create an inline-file the output must be redirected. If the output is incomplete then an error is retruned." ;; revoke) text=" * revoke [reason] Revoke a certificate specified by the , with an optional revocation reason which can be one of: unspecified keyCompromise CACompromise affiliationChanged superseded cessationOfOperation certificateHold" ;; revoke-renewed) text=" * revoke-renewed [reason] Revoke a *renewed* certificate specified by the , with an optional revocation reason which can be one of: unspecified keyCompromise CACompromise affiliationChanged superseded cessationOfOperation certificateHold" ;; rebuild) text=" * rebuild [ cmd-opts ] Rebuild a certificate and key specified by " opts=" * nopass - Do not encrypt the private key (Default: encrypted) (Equivalent to global option '--nopass|--no-pass')" ;; renew) text=" * renew Renew a certificate specified by " ;; rewind|rewind-renew) text=" * rewind-renew Rewind an EasyRSA version 3.0 'style' renewed certificate. Once 'rewind' has completed the certificate can be revoked by using: 'revoke-renewed [reason]' * NOTE: This does NOT 'unrenew' or 'unrevoke' a certificate. Ref : https://github.com/OpenVPN/easy-rsa/issues/578" ;; gen-crl) text=" * gen-crl Generate a certificate revocation list [CRL]" ;; update-db) text=" * update-db Update the index.txt database This command will use the system time to update the status of issued certificates." ;; make-safe-ssl) text=" * make-safe-ssl Generate a safe SSL config file" ;; show-req|show-cert) text=" * show-req [ cmd-opts ] * show-cert [ cmd-opts ] Shows details of the req or cert referenced by Human-readable output is shown, including any requested cert options when showing a request." opts=" * full - show full req/cert info, including pubkey/sig data" ;; show-ca) text=" * show-ca [ cmd-opts ] Shows details of the Certificate Authority [CA] certificate Human-readable output is shown." opts=" * full - show full CA info, including pubkey/sig data" ;; show-crl) text=" * show-crl Shows details of the current certificate revocation list (CRL) Human-readable output is shown." ;; show-expire) text=" * show-expire [ ] Shows details of *all* expiring certificates Use --renew-days=NN to extend the grace period (Default 90 days) Optionally, check *only* certificate" ;; show-revoke) text=" * show-revoke [ ] Shows details of *all* revoked certificates. Optionally, check *only* certificate" ;; show-renew) text=" * show-renew [ ] Shows details of renewed certificates, which have not been revoked Optionally, check *only* certificate" ;; verify|verify-cert) text=" * verify-cert [ cmd-opts ] Verify certificate against CA Returns the current validity of the certificate." opts=" * batch - On failure to verify, return error (1) to caller" ;; import-req) text=" * import-req Import a certificate request from a file This will copy the specified file into the reqs/ dir in preparation for signing. The is the to create. Example usage: import-req /some/where/bob_request.req bob" ;; export-p12) text=" * export-p12 [ cmd-opts ] Export a PKCS#12 file with the keypair, specified by " opts=" * nopass - Do not encrypt the private key (Default: encrypted) (Equivalent to global option '--nopass|--no-pass') * noca - Do not include the ca.crt file in the PKCS12 output * nokey - Do not include the private key in the PKCS12 output * usefn - Use as friendly name" ;; export-p7) text=" * export-p7 [ cmd-opts ] Export a PKCS#7 file with the pubkey, specified by " opts=" * noca - Do not include the ca.crt file in the PKCS7 output" ;; export-p8) text=" * export-p8 [ cmd-opts ] Export a PKCS#8 file with the private key, specified by " opts=" * nopass - Do not encrypt the private key (Default: encrypted) (Equivalent to global option '--nopass|--no-pass')" ;; export-p1) text=" * export-p1 [ cmd-opts ] Export a PKCS#1 (RSA format) file with the pubkey, specified by " opts=" * nopass - Do not encrypt the private key (Default: encrypted) (Equivalent to global option '--nopass|--no-pass')" ;; set-pass|set-ed-pass|set-rsa-pass|set-ec-pass) text=" * set-pass [ cmd-opts ] Set a new passphrase for the private key specified by DEPRECATED: 'set-rsa-pass' and 'set-ec-pass'" opts=" * nopass - Do not encrypt the private key (Default: encrypted) (Equivalent to global option '--nopass|--no-pass') * file - (Advanced) Treat the file as a raw path, not a short-name" ;; upgrade) text=" * upgrade Upgrade EasyRSA PKI and/or CA. Upgrade must be one of: * pki - Upgrade EasyRSA v2.x PKI to v3.x PKI (includes CA below) * ca - Upgrade EasyRSA v3.0.5 CA or older to v3.0.6 CA or later." ;; altname|subjectaltname|san) text_only=1 text=" * Option: --subject-alt-name=SAN_FORMAT_STRING This global option adds a subjectAltName to the request or issued certificate. It MUST be in a valid format accepted by openssl or req/cert generation will fail. Note that including multiple such names requires them to be comma-separated; further invocations of this option will REPLACE the value. Examples of the SAN_FORMAT_STRING shown below: * DNS:alternate.example.net * DNS:primary.example.net,DNS:alternate.example.net * IP:203.0.113.29 * email:alternate@example.net" ;; --days|days) text_only=1 text=" * Option: --days=DAYS This global option is an alias for one of the following: * Expiry days for a new CA. eg: '--days=3650 build-ca' * Expiry days for new/renewed certificate. eg: '--days=1095 renew server' * Expiry days for certificate revokation list. eg: '--days=180 gen-crl' * Cutoff days for command: show-expire. eg: '--days=90 show-expire'" ;; --req-cn|req-cn) text_only=1 text=" * Option: --req-cn=NAME This specific option can set the CSR commonName. Can only be used in BATCH mode for the following commands: * To build a new CA [or Sub-CA]: eg: '--batch --req-cn=NAME build-ca [subca]' * To generate a certificate signing request: eg: '--batch --req-cn=NAME gen-req '" ;; more|test|xtra|extra|ext) # Test features text_only=1 text=" Print vars.example here-doc to stdout: make-vars Make safessl-easyrsa.cnf file: mss|make-safe-ssl Check number is unique: serial|check-serial Display DN of certificate: display-dn Display SAN of certificate: display-san Generate default SAN of request: default-san Display EKU of certificate: x509-eku " ;; opts|options) opt_usage ;; "") usage ;; *) err_text=" Unknown command: '$1' \ (try without commands for a list of commands)" easyrsa_exit_with_error=1 esac if [ "$err_text" ]; then print "${err_text}" else # display the help text [ "$text" ] && print "$text" if [ "$text_only" ]; then : # ok - No opts message required else print " Available command options [ cmd-opts ]: ${opts:- * No supported command options}" fi fi } # => cmd_help() # Options usage opt_usage() { text_only=1 print " Easy-RSA Global Option Flags The following global-options may be provided before the command. Options specified at runtime override env-vars and any 'vars' file in use. Unless noted, non-empty values to options are mandatory. General options: --version : Prints EasyRSA version and build information --batch : Set automatic (no-prompts when possible) mode --silent|-s : Disable all warnings, notices and information --sbatch : Combined --silent and --batch operating mode --silent-ssl|-S : Silence SSL output (Requires batch mode) --nopass|no-pass: Do not use passwords Can NOT be used with --passin or --passout --passin=ARG : Set -passin ARG for openssl (eg: pass:xEasyRSAy) --passout=ARG : Set -passout ARG for openssl (eg: pass:xEasyRSAy) --raw|raw-ca : Build CA with password via RAW SSL input --vars=FILE : Define a specific 'vars' file to use for Easy-RSA config (Default vars file is in the current working directory) --pki=DIR : Declare the PKI directory (Default PKI directory is sub-directory 'pki') See Advanced.md for in depth usage. --ssl-conf=FILE : Define a specific OpenSSL config file for Easy-RSA to use (Default config file is in the EasyRSA PKI directory) --force-safe-ssl: Always generate a safe SSL config file (Default: Generate Safe SSL config once per instance) --tmp-dir=DIR : Declare the temporary directory (Default temporary directory is the EasyRSA PKI directory) --keep-tmp=NAME : Keep the original temporary session by name: NAME NAME is a sub-directory of the dir declared by --tmp-dir This option ALWAYS over-writes a sub-dir of the same name. Certificate & Request options: (these impact cert/req field values) --notext|no-text: Create certificates without human readable text --days=# : Sets the signing validity to the specified number of days Applies to other commands. For details, see: 'help days' --startdate=DATE: Sets the SSL option '-startdate' (Format 'YYYYMMDDhhmmssZ') --enddate=DATE : Sets the SSL option '-enddate' (Format 'YYYYMMDDhhmmssZ') --digest=ALG : Digest to use in the requests & certificates --keysize=# : Size in bits of keypair to generate (RSA Only) --use-algo=ALG : Crypto alg to use: choose rsa (default), ec or ed --curve=NAME : For elliptic curve, sets the named curve (Default: algo ec: secp384r1, algo ed: ed25519) --subca-len=# : Path length of signed intermediate CA certificates --copy-ext : Copy included request X509 extensions (namely subjAltName) --san|--subject-alt-name= : Add a subjectAltName. For more info and syntax, see: 'easyrsa help altname' Distinguished Name mode: --dn-mode=MODE : Distinguished Name mode to use 'cn_only' (Default) or 'org' --req-cn=NAME : Set CSR commonName to NAME. For details, see: 'help req-cn' Distinguished Name Organizational options: (only used with '--dn-mode=org') --req-c=CC : Country code (2-letters) --req-st=NAME : State/Province --req-city=NAME : City/Locality --req-org=NAME : Organization --req-email=NAME : Email addresses --req-ou=NAME : Organizational Unit --req-serial=VALUE : Entity serial number (Only used when declared) Deprecated features: --ns-cert : Include deprecated Netscape extensions --ns-comment=COMMENT : Include deprecated Netscape comment (may be blank)" } # => opt_usage() # Wrapper around printf - clobber print since it's not POSIX anyway # print() is used internally, so MUST NOT be silenced. # shellcheck disable=SC1117 print() { printf '%s\n' "$*" } # => print() # Exit fatally with a message to stderr # present even with EASYRSA_BATCH as these are fatal problems die() { print " Easy-RSA error: $1 " # error_info is currently unused if [ "$error_info" ]; then print "${error_info}${NL}" fi # show host info show_host # exit to cleanup() exit "${2:-1}" } # => die() # User errors, less noise than die() user_error() { print " EasyRSA version $EASYRSA_version Error ----- $1" easyrsa_exit_with_error=1 cleanup } # => user_error() # verbose information verbose() { [ "$EASYRSA_VERBOSE" ] || return 0 printf '%s\n' " > $*" } # => verbose() # non-fatal warning output warn() { [ "$EASYRSA_SILENT" ] && return print " WARNING ======= $1" } # => warn() # informational notices to stdout notice() { [ "$EASYRSA_SILENT" ] && return print " Notice ------ $1" } # => notice() # Helpful information information() { [ "$EASYRSA_SILENT" ] && return print "$1" } # => information() # intent confirmation helper func # returns without prompting in EASYRSA_BATCH confirm() { [ "$EASYRSA_BATCH" ] && return prompt="$1" value="$2" msg="$3" input="" print "\ $msg Type the word '$value' to continue, or any other input to abort." printf %s " $prompt" # shellcheck disable=SC2162 # read without -r will mangle .. read input printf '\n' [ "$input" = "$value" ] && return easyrsa_exit_with_error=1 notice "Aborting without confirmation." cleanup } # => confirm() # Generate random hex # Cannot use easyrsa-openssl() due to chicken vs egg, # easyrsa_openssl() creates temp-files, # which needs `openssl rand`. # Redirect error-out, ignore complaints of missing config easyrsa_random() { case "$1" in (*[!1234567890]*|0*|"") : ;; # invalid input (*) # Only return on success if OPENSSL_CONF=/dev/null \ "$EASYRSA_OPENSSL" rand -hex "$1" then return fi esac die "easyrsa_random failed" } # => easyrsa_random() # Create session directory atomically or fail secure_session() { # Session is already defined [ "$secured_session" ] && \ die "session overload" # temporary directory must exist if [ "$EASYRSA_TEMP_DIR" ] && \ [ -d "$EASYRSA_TEMP_DIR" ] then : # ok else die "secure_session - Missing temporary directory: * $EASYRSA_TEMP_DIR" fi for i in 1 2 3; do session="$( easyrsa_random 4 )" || die "secure_session - session" secured_session="${EASYRSA_TEMP_DIR}/${session}" # atomic: if mkdir "$secured_session"; then # New session requires safe-ssl conf unset -v mktemp_counter \ OPENSSL_CONF safe_ssl_cnf_tmp \ working_safe_ssl_conf easyrsa_err_log="$secured_session/error.log" verbose "\ secure_session: CREATED: $secured_session" return fi done die "secure_session failed" } # => secure_session() # Remove secure session remove_secure_session() { if [ "${secured_session%/*}" ] && \ [ -d "$secured_session" ] then # Always remove temp-session if rm -rf "$secured_session"; then verbose "\ remove_secure_session: DELETED: $secured_session" unset -v secured_session mktemp_counter \ OPENSSL_CONF safe_ssl_cnf_tmp \ working_safe_ssl_conf return fi fi die "remove_secure_session: $secured_session" } # => remove_secure_session() # Create temp-file atomically or fail # WARNING: Running easyrsa_openssl in a subshell # will hide error message and verbose messages # from easyrsa_mktemp() easyrsa_mktemp() { [ "$#" = 1 ] || die "\ easyrsa_mktemp - input error" # session directory must exist [ "$secured_session" ] || die "\ easyrsa_mktemp - Temporary session undefined" # Update counter mktemp_counter="$(( mktemp_counter + 1 ))" # Assign internal temp-file name t="${secured_session}/temp.${mktemp_counter}" # Create shotfile for h in x y z; do shotfile="${t}.${h}" if [ -e "$shotfile" ]; then verbose "\ easyrsa_mktemp: shot-file EXISTS: $shotfile" continue else printf "" > "$shotfile" || die "\ easyrsa_mktemp: create shotfile failed (1) $1" # Create temp-file or die # subshells do not update mktemp_counter, # which is why this extension is required. # Current max required is 3 attempts for i in 1 2 3 4 5 6 7 8 9; do want_tmp_file="${t}.${i}" # Warn to error log file for max reached [ "$EASYRSA_MAX_TEMP" -gt "$i" ] || print "\ Max temp-file limit $i, hit for: $1" >> "$easyrsa_err_log" if [ -e "$want_tmp_file" ]; then verbose "\ easyrsa_mktemp: temp-file EXISTS: $want_tmp_file" continue else # atomic: if [ "$easyrsa_host_os" = win ]; then set -o noclobber fi if mv "$shotfile" "$want_tmp_file"; then # Assign external temp-file name if force_set_var "$1" "$want_tmp_file" then verbose "\ easyrsa_mktemp: $1 OK: $want_tmp_file" if [ "$easyrsa_host_os" = win ]; then set +o noclobber fi unset -v want_tmp_file shotfile return else die "\ easyrsa_mktemp - force_set_var $1 failed" fi fi fi done fi done # In case of subshell abuse, report to error log err_msg="\ easyrsa_mktemp - failed for: $1 @ attempt=$i want_tmp_file: $want_tmp_file" print "$err_msg" >> "$easyrsa_err_log" die "$err_msg" } # => easyrsa_mktemp() # remove temp files and do terminal cleanups cleanup() { # In case of subshell abuse, display error log file if [ -f "$easyrsa_err_log" ]; then print cat "$easyrsa_err_log" print fi if [ "${secured_session%/*}" ] && \ [ -d "$secured_session" ] then # Remove temp-session or create temp-snapshot if [ "$EASYRSA_KEEP_TEMP" ] then # skip on black-listed directory names, with a warning if [ -e "$EASYRSA_TEMP_DIR/$EASYRSA_KEEP_TEMP" ] then warn "\ Prohibited value for --keep-tmp: '$EASYRSA_KEEP_TEMP' Temporary session not preserved." else # create temp-snapshot keep_tmp="$EASYRSA_TEMP_DIR/tmp/$EASYRSA_KEEP_TEMP" mkdir -p "$keep_tmp" rm -rf "$keep_tmp" mv -f "$secured_session" "$keep_tmp" print "Temp session preserved: $keep_tmp" fi else # remove temp-session remove_secure_session || \ warn "cleanup - remove_secure_session failed" fi fi # These cleanup routines must be called after die() # because the relate commands can die in subshells. # Remove files when build_full()->sign_req() is interrupted [ "$error_build_full_cleanup" ] && \ rm -f "$crt_out" "$req_out" "$key_out" # Restore files when renew is interrupted [ "$error_undo_renew_move" ] && renew_restore_move # Restore files when rebuild is interrupted [ "$error_undo_rebuild_move" ] && rebuild_restore_move # shellcheck disable=SC3040 # In POSIX sh, set option [name] is undefined case "$prompt_restore" in 0) : ;; # Not required 1) [ -t 1 ] && stty echo ;; 2) set -o echo ;; *) warn "prompt_restore: '$prompt_restore'" esac # Get a clean line [ "$EASYRSA_SILENT" ] || print # Clear traps trap - 0 1 2 3 6 15 # Exit: Known errors # -> confirm(): aborted # -> verify_cert(): verify failed --batch mode # -> check_serial_unique(): not unique --batch mode # -> user_error(): User errors but not die() if [ "$easyrsa_exit_with_error" ]; then verbose "Exit: Known errors = true" exit 1 fi # Exit: SIGINT if [ "$1" = 2 ]; then verbose "exit SIGINT = true" kill -2 "$$" fi # Exit: Final Success if [ "$1" = ok ]; then # if there is no error # then 'cleanup ok' is called verbose "Exit: Final Success = true" exit 0 fi # Exit: Final Fail # if 'cleanup' is called without 'ok' # then an error occurred verbose "Exit: Final Fail = true" exit 1 } # => cleanup() # Make a copy safe SSL config file make_safe_ssl() { easyrsa_openssl makesafeconf notice "\ Safe SSL config file created at: * $EASYRSA_SAFE_CONF" verbose "\ make_safe_ssl: NEW SSL cnf file: $safe_ssl_cnf_tmp" } # => make_safe_ssl_copy() # Escape hazardous characters # Auto-escape hazardous characters: # '&' - Workaround 'sed' behavior # '$' - Workaround 'easyrsa' based limitation # This is required for all SSL libs, otherwise, # there are unacceptable differences in behavior escape_hazard() { if [ "$EASYRSA_FORCE_SAFE_SSL" ] || \ [ "$makesafeconf" ] then # Always run verbose "escape_hazard: FORCED" elif [ "$working_safe_org_conf" ]; then # Has run once verbose "escape_hazard: BYPASSED" return else # Run once verbose "escape_hazard: RUN-ONCE" fi # Set run once working_safe_org_conf=1 # Assign temp-file escape_hazard_tmp="" easyrsa_mktemp escape_hazard_tmp || die \ "escape_hazard - easyrsa_mktemp escape_hazard_tmp" # write org fields to org temp-file and escape '&' and '$' print "\ export EASYRSA_REQ_COUNTRY=\"$EASYRSA_REQ_COUNTRY\" export EASYRSA_REQ_PROVINCE=\"$EASYRSA_REQ_PROVINCE\" export EASYRSA_REQ_CITY=\"$EASYRSA_REQ_CITY\" export EASYRSA_REQ_ORG=\"$EASYRSA_REQ_ORG\" export EASYRSA_REQ_OU=\"$EASYRSA_REQ_OU\" export EASYRSA_REQ_EMAIL=\"$EASYRSA_REQ_EMAIL\" export EASYRSA_REQ_SERIAL=\"$EASYRSA_REQ_SERIAL\"\ " | sed -e s\`'\&'\`'\\\&'\`g \ -e s\`'\$'\`'\\\$'\`g \ > "$escape_hazard_tmp" || die "\ escape_hazard - Failed to write temp-file" # Reload fields from fully escaped temp-file # shellcheck disable=SC1090 # can't follow ... (. "$escape_hazard_tmp") || die "\ escape_hazard - Failed to source temp-file" verbose "escape_hazard: COMPLETED" # shellcheck disable=SC1090 # can't follow ... . "$escape_hazard_tmp" } # => escape_hazard() # Replace environment variable names with current value # and write to temp-file or return error from sed expand_ssl_config() { if [ "$EASYRSA_FORCE_SAFE_SSL" ] || \ [ "$makesafeconf" ] then # Always run verbose "expand_ssl_config: FORCED" elif [ "$working_safe_ssl_conf" ]; then # Has run once verbose "expand_ssl_config: BYPASSED" return elif [ "$ssl_lib" = libressl ]; then # Always run verbose "expand_ssl_config: REQUIRED" elif [ "$ssl_lib" = openssl ]; then # OpenSSl does not require a safe config verbose "expand_ssl_config: IGNORED" return else # do NOT Run die "expand_ssl_config: EXCEPTION" fi # Set run once working_safe_ssl_conf=1 verbose "expand_ssl_config: RUN-ONCE" # Assign temp-file safe_ssl_cnf_tmp="" easyrsa_mktemp safe_ssl_cnf_tmp || die "\ expand_ssl_config - \ easyrsa_mktemp safe_ssl_cnf_tmp" # Rewrite # shellcheck disable=SC2016 # No expansion inside '' if sed \ \ -e s\`'$dir'\`\ \""$EASYRSA_PKI"\"\`g \ \ -e s\`'$ENV::EASYRSA_PKI'\`\ \""$EASYRSA_PKI"\"\`g \ \ -e s\`'$ENV::EASYRSA_CERT_EXPIRE'\`\ \""$EASYRSA_CERT_EXPIRE"\"\`g \ \ -e s\`'$ENV::EASYRSA_CRL_DAYS'\`\ \""$EASYRSA_CRL_DAYS"\"\`g \ \ -e s\`'$ENV::EASYRSA_DIGEST'\`\ \""$EASYRSA_DIGEST"\"\`g \ \ -e s\`'$ENV::EASYRSA_KEY_SIZE'\`\ \""$EASYRSA_KEY_SIZE"\"\`g \ \ -e s\`'$ENV::EASYRSA_DN'\`\ \""$EASYRSA_DN"\"\`g \ \ -e s\`'$ENV::EASYRSA_REQ_CN'\`\ \""$EASYRSA_REQ_CN"\"\`g \ \ -e s\`'$ENV::EASYRSA_REQ_COUNTRY'\`\ \""$EASYRSA_REQ_COUNTRY"\"\`g \ \ -e s\`'$ENV::EASYRSA_REQ_PROVINCE'\`\ \""$EASYRSA_REQ_PROVINCE"\"\`g \ \ -e s\`'$ENV::EASYRSA_REQ_CITY'\`\ \""$EASYRSA_REQ_CITY"\"\`g \ \ -e s\`'$ENV::EASYRSA_REQ_ORG'\`\ \""$EASYRSA_REQ_ORG"\"\`g \ \ -e s\`'$ENV::EASYRSA_REQ_OU'\`\ \""$EASYRSA_REQ_OU"\"\`g \ \ -e s\`'$ENV::EASYRSA_REQ_EMAIL'\`\ \""$EASYRSA_REQ_EMAIL"\"\`g \ \ -e s\`'$ENV::EASYRSA_REQ_SERIAL'\`\ \""$EASYRSA_REQ_SERIAL"\"\`g \ \ "$EASYRSA_SSL_CONF" > "$safe_ssl_cnf_tmp" then verbose "expand_ssl_config: COMPLETED" else return 1 fi } # => expand_ssl_config() # Easy-RSA meta-wrapper for SSL # WARNING: Running easyrsa_openssl in a subshell # will hide error message and verbose messages # # The expansion here takes place on EASYRSA_SSL_CONF, # which may have already been replaced by a temp-file # with the extensions having been inserted by build-ca, # sign-req or gen-req. easyrsa_openssl() { openssl_command="$1"; shift # Do not allow 'rand' here, see easyrsa_random() case "$openssl_command" in rand) die "easyrsa_openssl: Illegal SSL command: rand" ;; makesafeconf) makesafeconf=1 ;; *) : esac # Auto-escape hazardous characters escape_hazard || \ die "easyrsa_openssl - escape_hazard failed" # Rewrite SSL config expand_ssl_config || \ die "easyrsa_openssl - expand_ssl_config failed" # VERIFY safe temp-file exists if [ -e "$safe_ssl_cnf_tmp" ]; then verbose "\ easyrsa_openssl: Safe SSL conf OK: $safe_ssl_cnf_tmp" export OPENSSL_CONF="$safe_ssl_cnf_tmp" else verbose "\ easyrsa_openssl: No Safe SSL conf, FALLBACK to default" export OPENSSL_CONF="$EASYRSA_SSL_CONF" fi # Execute command - Return on success if [ "$openssl_command" = "makesafeconf" ]; then # COPY temp-file to safessl-easyrsa.cnf unset -v makesafeconf cp -f "$safe_ssl_cnf_tmp" "$EASYRSA_SAFE_CONF" && \ return die "easyrsa_openssl: makesafeconf FAILED" fi # Exec SSL if [ "$EASYRSA_SILENT_SSL" ] && [ "$EASYRSA_BATCH" ] then "$EASYRSA_OPENSSL" "$openssl_command" "$@" \ 2>/dev/null && \ return else "$EASYRSA_OPENSSL" "$openssl_command" "$@" && \ return fi # Always fail here die "\ easyrsa_openssl - Command has failed: * $EASYRSA_OPENSSL $openssl_command $*" } # => easyrsa_openssl() # Verify the SSL library is functional # and establish version dependencies verify_ssl_lib() { # Run once only [ "$verify_ssl_lib_ok" ] && return verify_ssl_lib_ok=1 unset -v openssl_v3 # redirect std-err, ignore missing ssl/openssl.cnf val="$( OPENSSL_CONF=/dev/null "$EASYRSA_OPENSSL" version )" ssl_version="$val" # SSL lib name case "${val%% *}" in OpenSSL) ssl_lib=openssl ;; LibreSSL) ssl_lib=libressl ;; *) error_msg="$("$EASYRSA_OPENSSL" version 2>&1)" user_error "\ * OpenSSL must either exist in your PATH or be defined in your vars file. Invalid SSL output for 'version': $error_msg" esac # Set SSL version dependent $no_password option osslv_major="${val#* }" osslv_major="${osslv_major%%.*}" case "$osslv_major" in 1) no_password='-nodes' ;; 2) no_password='-nodes' ;; 3) case "$ssl_lib" in openssl) openssl_v3=1 no_password='-noenc' ;; libressl) no_password='-nodes' ;; *) die "Unexpected SSL library: $ssl_lib" esac ;; *) die "Unexpected SSL version: $osslv_major" esac } # => verify_ssl_lib() # Basic sanity-check of PKI init and complain if missing verify_pki_init() { help_note="\ Run easyrsa without commands for usage and command help." # Check for defined EASYRSA_PKI [ "$EASYRSA_PKI" ] || die "\ EASYRSA_PKI env-var undefined" # check that the pki dir exists [ -d "$EASYRSA_PKI" ] || user_error "\ EASYRSA_PKI does not exist (perhaps you need to run init-pki)? Expected to find the EASYRSA_PKI at: * $EASYRSA_PKI $help_note" # verify expected dirs present: for i in private reqs; do [ -d "$EASYRSA_PKI/$i" ] || user_error "\ Missing expected directory: $i (perhaps you need to run init-pki?) $help_note" done unset -v help_note } # => verify_pki_init() # Verify core CA files present verify_ca_init() { help_note="\ Run easyrsa without commands for usage and command help." # Verify expected files are present. # Allow files to be regular files (or symlinks), # but also pipes, for flexibility with ca.key for i in ca.crt private/ca.key \ index.txt index.txt.attr serial do if [ ! -f "$EASYRSA_PKI/$i" ] && \ [ ! -p "$EASYRSA_PKI/$i" ] then [ "$1" = "test" ] && return 1 user_error "\ Missing expected CA file: $i (perhaps you need to run build-ca?) $help_note" fi done # When operating in 'test' mode, return success. # test callers don't care about CA-specific dir structure [ "$1" = "test" ] && return 0 # verify expected CA-specific dirs: for i in issued certs_by_serial do [ -d "$EASYRSA_PKI/$i" ] || user_error "\ Missing expected CA dir: $i (perhaps you need to run build-ca?) $help_note" done # explicitly return success for callers unset -v help_note return 0 } # => verify_ca_init() # init-pki backend: init_pki() { # Process command options reset="hard" while [ "$1" ]; do case "$1" in hard-reset|hard) reset="hard" ;; soft-reset|soft) reset="soft" ;; *) warn "Ignoring unknown command option: '$1'" esac shift done # EasyRSA will NOT do 'rm -rf /' case "$EASYRSA_PKI" in .|..|./|../|.//*|..//*|/|//*|\\|?:|'') user_error "Invalid PKI: $EASYRSA_PKI" esac # If EASYRSA_PKI exists, confirm before deletion if [ -e "$EASYRSA_PKI" ]; then confirm "Confirm removal: " "yes" " WARNING!!! You are about to remove the EASYRSA_PKI at: * $EASYRSA_PKI and initialize a fresh PKI here." # now remove it: case "$reset" in hard) # # # shellcheck disable=SC2115 # Use "${var:?}" rm -rf "$EASYRSA_PKI" || \ die "init-pki hard reset failed." ;; soft) # There is no unit test for a soft reset for i in ca.crt crl.pem \ issued private reqs inline revoked renewed \ serial serial.old index.txt index.txt.old \ index.txt.attr index.txt.attr.old \ ecparams certs_by_serial do # # # shellcheck disable=SC2115 # Use "${var:?}" target="$EASYRSA_PKI/$i" if [ "${target%/*}" ]; then rm -rf "$target" || \ die "init-pki soft reset(1) failed!" else die "init-pki soft reset(2) failed!" fi done ;; *) user_error "Unknown reset type: $reset" esac fi # new dirs: for i in private reqs inline; do mkdir -p "$EASYRSA_PKI/$i" || \ die "\ Failed to create PKI file structure (permissions?)" done # Install data-files into ALL new PKIs install_data_to_pki init-pki || \ warn "\ Failed to install required data-files to PKI. (init)" notice "\ 'init-pki' complete; you may now create a CA or requests. Your newly created PKI dir is: * $EASYRSA_PKI" # Installation information # if $no_new_vars then there are one or more known vars # which are not in the PKI. All further commands will fail # until vars is manually corrected if [ "$no_new_vars" ]; then warn "\ A vars file has not been created in your new PKI because conflicting vars files have been found elsewhere." prefer_vars_in_pki_msg else unset -v EASYRSA_VARS_FILE select_vars information " Using Easy-RSA configuration: * ${EASYRSA_VARS_FILE:-undefined}" fi # For new PKIs , pki/vars was auto-created, show message if [ "$new_vars_true" ]; then information " IMPORTANT: Easy-RSA 'vars' template file has been created in your new PKI. Edit this 'vars' file to customise the settings for your PKI. To use a global vars file, use global option --vars=" else prefer_vars_in_pki_msg fi verbose "\ init_pki: x509-types dir ${EASYRSA_EXT_DIR:-Not found}" } # => init_pki() # Must be used in two places, so made it a function prefer_vars_in_pki_msg() { if [ "$vars_in_pki" ] || [ "$user_vars_true" ] || [ "$EASYRSA_NO_VARS" ] then return fi # Never show this message return information " IMPORTANT: The preferred location for 'vars' is within the PKI folder. To silence this message move your 'vars' file to your PKI or declare your 'vars' file with option: --vars=" } # => prefer_vars_in_pki_msg() # Copy data-files from various sources install_data_to_pki() { # # Explicitly find and optionally copy data-files to the PKI. # During 'init-pki' this is the new default. # During all other functions these requirements are tested for # and files will be copied to the PKI, if they do not already # exist there. # # One reason for this is to make packaging work. context="$1" shift # Set required sources vars_file='vars' vars_file_example='vars.example' ssl_cnf_file='openssl-easyrsa.cnf' x509_types_dir='x509-types' # "$EASYRSA_PKI" - Preferred # "$EASYRSA" - Old default and Windows # "$PWD" - Usually the same as above, avoid # "${0%/*}" - Usually the same as above, avoid # '/usr/local/share/easy-rsa' - Default user installed # '/usr/share/easy-rsa' - Default system installed # Room for more.. # '/etc/easy-rsa' - Last resort # Find and optionally copy data-files, in specific order for area in \ "$EASYRSA_PKI" \ "$EASYRSA" \ "$PWD" \ "${0%/*}" \ '/usr/local/share/easy-rsa' \ '/usr/share/easy-rsa' \ '/etc/easy-rsa' \ # EOL do if [ "$context" = x509-types-only ]; then # Find x509-types ONLY # Declare in preferred order, first wins # beaten by command line. [ -e "${area}/${x509_types_dir}" ] && set_var \ EASYRSA_EXT_DIR "${area}/${x509_types_dir}" else # Find x509-types ALSO # Declare in preferred order, first wins # beaten by command line. [ -e "${area}/${x509_types_dir}" ] && set_var \ EASYRSA_EXT_DIR "${area}/${x509_types_dir}" # Find other files - Omitting "$vars_file" # shellcheck disable=2066 # Loop will only run once for source in \ "$ssl_cnf_file" \ # EOL do # Find each item [ -e "${area}/${source}" ] || continue # If source does not exist in PKI then copy it if [ -e "${EASYRSA_PKI}/${source}" ]; then continue else cp "${area}/${source}" "$EASYRSA_PKI" || die \ "Failed to copy to PKI: ${area}/${source}" fi done fi done # Short circuit for x509-types-only if [ "$context" = x509-types-only ]; then verbose "\ install_data_to_pki: $context - COMPLETED" return fi # Create PKI/vars from PKI/example unset -v new_vars_true if [ "$user_vars_true" ] || \ [ "$no_new_vars" ] then : # ok - Do not make a PKI/vars if another vars exists verbose "\ install_data_to_pki: $context - Not creating pki/vars" else case "$context" in init-pki) # Only create for 'init-pki', if one does not exist # 'init-pki soft' should have it's own 'vars' file if [ -e "${EASYRSA_PKI}/${vars_file_example}" ] && \ [ ! -e "${EASYRSA_PKI}/${vars_file}" ] then # Failure means that no vars will exist and # 'cp' will generate an error message # This is not a fatal error if cp "${EASYRSA_PKI}/${vars_file_example}" \ "${EASYRSA_PKI}/${vars_file}" then new_vars_true=1 vars="${EASYRSA_PKI}/${vars_file}" verbose "\ install_data_to_pki: $context - vars = '$vars'" else unset -v new_vars_true vars warn "\ install_data_to_pki: $context - Failed to install vars file" fi fi ;; vars-setup) : ;; # No change to current 'vars' required x509-types-only) die "install_data_to_pki - unexpected context" ;; '') die "install_data_to_pki - unspecified context" ;; *) die "install_data_to_pki - unknown context: $context" esac fi # Check PKI is updated - Omit unnecessary checks if [ -e "${EASYRSA_PKI}/${ssl_cnf_file}" ]; then : # ok else create_openssl_easyrsa_cnf > \ "${EASYRSA_PKI}/${ssl_cnf_file}" || die "\ install_data_to_pki - Missing: '$ssl_cnf_file'" verbose "\ install_data_to_pki: $context - create_openssl_easyrsa_cnf OK" fi [ -d "$EASYRSA_EXT_DIR" ] || verbose "\ install_data_to_pki: $context - Missing: '$x509_types_dir'" verbose "install_data_to_pki: $context - COMPLETED" } # => install_data_to_pki () # Disable terminal echo, if possible, otherwise warn hide_read_pass() { # 3040 - In POSIX sh, set option [name] is undefined # 3045 - In POSIX sh, some-command-with-flag is undefined # shellcheck disable=SC3040,SC3045 if stty -echo 2>/dev/null; then prompt_restore=1 read -r "$@" stty echo elif (set +o echo 2>/dev/null); then prompt_restore=2 set +o echo read -r "$@" set -o echo elif (echo | read -r -s 2>/dev/null) ; then read -r -s "$@" else warn "\ Could not disable echo. Password will be shown on screen!" read -r "$@" fi prompt_restore=0 return 0 } # => hide_read_pass() # Get passphrase get_passphrase() { t="$1"; shift || die "password malfunction" while :; do r="" printf '\n%s' "$*" hide_read_pass r if [ "${#r}" -lt 4 ]; then printf '\n%s\n' \ "Passphrase must be at least 4 characters!" else force_set_var "$t" "$r" || die "Passphrase error!" unset -v r t print return 0 fi done } # => get_passphrase() # build-ca backend: build_ca() { cipher="-aes256" unset -v sub_ca ssl_batch date_stamp x509 error_info while [ "$1" ]; do case "$1" in intca|subca) sub_ca=1 ;; nopass) [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; raw-ca|raw) EASYRSA_RAW_CA=1 ;; *) warn "Ignoring unknown command option: '$1'" esac shift done out_key="$EASYRSA_PKI/private/ca.key" # setup for an intermediate CA if [ "$sub_ca" ]; then # Generate a CSR out_file="$EASYRSA_PKI/reqs/ca.req" else # Generate a certificate out_file="$EASYRSA_PKI/ca.crt" date_stamp=1 x509=1 fi # RAW mode must take priority if [ "$EASYRSA_RAW_CA" ]; then unset -v EASYRSA_NO_PASS EASYRSA_PASSOUT EASYRSA_PASSIN verbose "build-ca: CA password RAW method" else # If encrypted then create the CA key with AES256 cipher if [ "$EASYRSA_NO_PASS" ]; then unset -v cipher else unset -v no_password fi fi # Test for existing CA, and complain if already present if verify_ca_init test; then user_error "\ Unable to create a CA as you already seem to have one set up. If you intended to start a new CA, run init-pki first." fi # If a private key exists, an intermediate ca was created # but not signed. # Notify user and require a signed ca.crt or a init-pki: if [ -f "$out_key" ]; then user_error "\ A CA private key exists but no ca.crt is found in your PKI: * $EASYRSA_PKI Refusing to create a new CA as this would overwrite your current CA. To start a new CA, run init-pki first." fi # create necessary dirs: err_msg="\ Unable to create necessary PKI files (permissions?)" for i in issued certs_by_serial \ revoked/certs_by_serial revoked/private_by_serial \ revoked/reqs_by_serial do mkdir -p "$EASYRSA_PKI/$i" || die "$err_msg" done # create necessary files: printf "" > \ "$EASYRSA_PKI/index.txt" || die "$err_msg" printf '%s\n' 'unique_subject = no' \ > "$EASYRSA_PKI/index.txt.attr" || die "$err_msg" printf '%s\n' "01" \ > "$EASYRSA_PKI/serial" || die "$err_msg" unset -v err_msg # Set ssl batch mode, as required # --req-cn must be used with --batch, # otherwise use default if [ "$EASYRSA_BATCH" ]; then ssl_batch=1 else export EASYRSA_REQ_CN=ChangeMe fi # Default CA commonName if [ "$EASYRSA_REQ_CN" = ChangeMe ]; then if [ "$sub_ca" ]; then export EASYRSA_REQ_CN="Easy-RSA Sub-CA" else export EASYRSA_REQ_CN="Easy-RSA CA" fi fi # Check for insert-marker in ssl config file if [ "$EASYRSA_EXTRA_EXTS" ]; then if ! grep -q '^#%CA_X509_TYPES_EXTRA_EXTS%' \ "$EASYRSA_SSL_CONF" then die "\ This openssl config file does \ not support X509-type 'ca'. * $EASYRSA_SSL_CONF Please update 'openssl-easyrsa.cnf' \ to the latest Easy-RSA release." fi fi # Assign cert and key temp files out_key_tmp="" easyrsa_mktemp out_key_tmp || \ die "build_ca - easyrsa_mktemp out_key_tmp" out_file_tmp="" easyrsa_mktemp out_file_tmp || \ die "build_ca - easyrsa_mktemp out_file_tmp" # Get passphrase from user if necessary if [ "$EASYRSA_RAW_CA" ] then # Passphrase will be provided confirm " Accept ? " yes "\ Raw CA mode =========== CA password must be input THREE times: 1. Set the password. 2. Confirm the password. 3. Use the password. (Create the Root CA)" elif [ "$EASYRSA_NO_PASS" ] then : # No passphrase required elif [ "$EASYRSA_PASSOUT" ] && [ "$EASYRSA_PASSIN" ] then : # passphrase defined # Both --passout and --passin # must be defined for a CA with a password else # Assign passphrase vars # Heed shellcheck SC2154 p="" q="" # Get passphrase p get_passphrase p \ "Enter New CA Key Passphrase: " # Confirm passphrase q get_passphrase q \ "Confirm New CA Key Passphrase: " # Validate passphrase if [ "$p" ] && [ "$p" = "$q" ]; then # CA password via temp-files in_key_pass_tmp="" easyrsa_mktemp in_key_pass_tmp || \ die "build_ca - in_key_pass_tmp" out_key_pass_tmp="" easyrsa_mktemp out_key_pass_tmp || \ die "build_ca - out_key_pass_tmp" printf "%s" "$p" > "$in_key_pass_tmp" || \ die "in_key_pass_tmp: write" printf "%s" "$p" > "$out_key_pass_tmp" || \ die "out_key_pass_tmp: write" unset -v p q else unset -v p q user_error "Passphrases do not match!" fi fi # Assign tmp-file for config raw_ssl_cnf_tmp="" easyrsa_mktemp raw_ssl_cnf_tmp || \ die "build_ca - easyrsa_mktemp raw_ssl_cnf_tmp" # Assign awkscript to insert EASYRSA_EXTRA_EXTS # shellcheck disable=SC2016 # vars don't expand in '' awkscript='\ {if ( match($0, "^#%CA_X509_TYPES_EXTRA_EXTS%") ) { while ( getline<"/dev/stdin" ) {print} next } {print} }' # Insert x509-types COMMON and 'ca' and EASYRSA_EXTRA_EXTS { # 'ca' file if [ -f "$EASYRSA_EXT_DIR/ca" ]; then cat "$EASYRSA_EXT_DIR/ca" else create_x509_type ca fi # COMMON file if [ -f "$EASYRSA_EXT_DIR/COMMON" ]; then cat "$EASYRSA_EXT_DIR/COMMON" else create_x509_type COMMON fi # User extentions [ "$EASYRSA_EXTRA_EXTS" ] && \ print "$EASYRSA_EXTRA_EXTS" } | awk "$awkscript" "$EASYRSA_SSL_CONF" \ > "$raw_ssl_cnf_tmp" || \ die "Copying X509_TYPES to config file failed" verbose "build-ca: insert x509 and extensions OK" # Use this new SSL config for the rest of this function EASYRSA_SSL_CONF="$raw_ssl_cnf_tmp" # Generate CA Key if [ "$EASYRSA_RAW_CA" ]; then case "$EASYRSA_ALGO" in rsa) if easyrsa_openssl genpkey \ -algorithm "$EASYRSA_ALGO" \ -pkeyopt \ rsa_keygen_bits:"$EASYRSA_ALGO_PARAMS" \ -out "$out_key_tmp" \ ${cipher:+ "$cipher"} then : # ok else die "Failed create CA private key" fi ;; ec) if easyrsa_openssl genpkey \ -paramfile "$EASYRSA_ALGO_PARAMS" \ -out "$out_key_tmp" \ ${cipher:+ "$cipher"} then : # ok else die "Failed create CA private key" fi ;; ed) if easyrsa_openssl genpkey \ -algorithm "$EASYRSA_CURVE" \ -out "$out_key_tmp" \ ${cipher:+ "$cipher"} then : # ok else die "Failed create CA private key" fi ;; *) die "Unknown algorithm: $EASYRSA_ALGO" esac verbose "\ build_ca: CA key password created via RAW" else case "$EASYRSA_ALGO" in rsa) easyrsa_openssl genpkey \ -algorithm "$EASYRSA_ALGO" \ -pkeyopt rsa_keygen_bits:"$EASYRSA_ALGO_PARAMS" \ -out "$out_key_tmp" \ ${cipher:+ "$cipher"} \ ${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \ ${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \ || die "Failed create CA private key" ;; ec) easyrsa_openssl genpkey \ -paramfile "$EASYRSA_ALGO_PARAMS" \ -out "$out_key_tmp" \ ${cipher:+ "$cipher"} \ ${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \ ${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \ || die "Failed create CA private key" ;; ed) easyrsa_openssl genpkey \ -algorithm "$EASYRSA_CURVE" \ -out "$out_key_tmp" \ ${cipher:+ "$cipher"} \ ${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \ ${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \ || die "Failed create CA private key" ;; *) die "Unknown algorithm: $EASYRSA_ALGO" esac [ "$EASYRSA_NO_PASS" ] || verbose "\ build_ca: CA key password created via temp-files" fi # Generate the CA keypair: if [ "$EASYRSA_RAW_CA" ]; then if easyrsa_openssl req -utf8 -new \ -key "$out_key_tmp" \ -out "$out_file_tmp" \ ${x509:+ -x509} \ ${date_stamp:+ -days "$EASYRSA_CA_EXPIRE"} \ ${EASYRSA_DIGEST:+ -"$EASYRSA_DIGEST"} then : # ok unset -v error_info else die "Failed to build the CA keypair." fi verbose "\ build_ca: CA certificate password created via RAW" else easyrsa_openssl req -utf8 -new \ -key "$out_key_tmp" -keyout "$out_key_tmp" \ -out "$out_file_tmp" \ ${ssl_batch:+ -batch} \ ${x509:+ -x509} \ ${date_stamp:+ -days "$EASYRSA_CA_EXPIRE"} \ ${EASYRSA_DIGEST:+ -"$EASYRSA_DIGEST"} \ ${EASYRSA_NO_PASS:+ "$no_password"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \ ${in_key_pass_tmp:+ -passin file:"$in_key_pass_tmp"} \ ${out_key_pass_tmp:+ -passout file:"$out_key_pass_tmp"} \ || die "Failed to build the CA keypair" [ "$EASYRSA_NO_PASS" ] || verbose "\ build_ca: CA certificate password created via temp-files" fi # Move temp-files to output files mv "$out_key_tmp" "$out_key" || { die "Failed to move key temp-file" } mv "$out_file_tmp" "$out_file" || { rm -f "$out_key" # Also remove the key die "Failed to move cert temp-file" } # Success messages if [ "$sub_ca" ]; then notice "\ Your intermediate CA request is at: * $out_file and now must be sent to your parent CA for signing. Place your resulting cert at: * $EASYRSA_PKI/ca.crt prior to signing operations." else notice "\ CA creation complete. Your new CA certificate is at: * $out_file" fi return 0 } # => build_ca() # gen-dh backend: gen_dh() { out_file="$EASYRSA_PKI/dh.pem" # check to see if we already have a dh parameters file if [ -e "$out_file" ]; then if [ "$EASYRSA_BATCH" ]; then # if batch is enabled, die user_error "\ DH parameters file already exists at: $out_file" else # warn the user, allow to force overwrite confirm "Overwrite? " "yes" "\ DH parameters file already exists at: $out_file" fi fi # Create a temp file # otherwise user abort leaves an incomplete dh.pem tmp_dh_file="" easyrsa_mktemp tmp_dh_file || \ die "gen_dh - easyrsa_mktemp tmp_dh_file" # Generate dh.pem OPENSSL_CONF=/dev/null \ "$EASYRSA_OPENSSL" dhparam -out "$tmp_dh_file" \ "$EASYRSA_KEY_SIZE" || \ die "Failed to generate DH params" # Validate dh.pem OPENSSL_CONF=/dev/null \ "$EASYRSA_OPENSSL" dhparam -in "$tmp_dh_file" \ -check -noout || \ die "Failed to validate DH params" mv -f "$tmp_dh_file" "$out_file" || \ die "Failed to move temp DH file" notice " DH parameters of size $EASYRSA_KEY_SIZE created at: * $out_file" return 0 } # => gen_dh() # gen-req and key backend: gen_req() { # pull filename, use as default interactive CommonName [ "$1" ] || user_error "\ Error: gen-req must have a file-name-base as the first argument. Run easyrsa without commands for usage and commands." file_name_base="$1" shift # scrape off file-name-base # Initialisation unset -v text ssl_batch # Set ssl batch mode and Default commonName, as required if [ "$EASYRSA_BATCH" ]; then ssl_batch=1 # If EASYRSA_REQ_CN is set to something other than # 'ChangeMe' then keep user defined value if [ "$EASYRSA_REQ_CN" = ChangeMe ]; then export EASYRSA_REQ_CN="$file_name_base" fi else # --req-cn must be used with --batch # otherwise use file-name export EASYRSA_REQ_CN="$file_name_base" fi # Output files key_out="$EASYRSA_PKI/private/${file_name_base}.key" req_out="$EASYRSA_PKI/reqs/${file_name_base}.req" # function opts support while [ "$1" ]; do case "$1" in text) text=1 ;; nopass) [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; # batch flag supports internal caller build_full() batch) ssl_batch=1 ;; *) warn "Ignoring unknown command option: '$1'" esac shift done # don't wipe out an existing private key without confirmation if [ -f "$key_out" ]; then confirm "Confirm key overwrite: " "yes" "\ WARNING!!! An existing private key was found at $key_out Continuing with key generation will replace this key." fi # When EASYRSA_EXTRA_EXTS is defined, # append it to openssl's [req] section: if [ "$EASYRSA_EXTRA_EXTS" ]; then # Check for insert-marker in ssl config file if ! grep -q '^#%EXTRA_EXTS%' "$EASYRSA_SSL_CONF" then die "\ This openssl config file does \ does not support EASYRSA_EXTRA_EXTS. * $EASYRSA_SSL_CONF Please update 'openssl-easyrsa.cnf' \ to the latest Easy-RSA release." fi # Setup & insert the extra ext data keyed by magic line extra_exts=" req_extensions = req_extra [ req_extra ] $EASYRSA_EXTRA_EXTS" # vars don't expand in single quote # shellcheck disable=SC2016 awkscript=' {if ( match($0, "^#%EXTRA_EXTS%") ) { while ( getline<"/dev/stdin" ) {print} next } {print} }' # Assign temp-file for confg raw_ssl_cnf_tmp="" easyrsa_mktemp raw_ssl_cnf_tmp || \ die "gen_req - easyrsa_mktemp raw_ssl_cnf_tmp" # Insert $extra_exts @ %EXTRA_EXTS% in SSL Config print "$extra_exts" | \ awk "$awkscript" "$EASYRSA_SSL_CONF" \ > "$raw_ssl_cnf_tmp" || \ die "Writing SSL config to temp file failed" # Use this SSL config for the rest of this function EASYRSA_SSL_CONF="$raw_ssl_cnf_tmp" fi # Name temp files key_out_tmp="" easyrsa_mktemp key_out_tmp || \ die "gen_req - easyrsa_mktemp key_out_tmp" req_out_tmp="" easyrsa_mktemp req_out_tmp || \ die "gen_req - easyrsa_mktemp req_out_tmp" # Set algorithm options algo_opts="" case "$EASYRSA_ALGO" in rsa|ec) # Set elliptic curve parameters-file # or RSA bit-length algo_opts="$EASYRSA_ALGO:$EASYRSA_ALGO_PARAMS" ;; ed) # Set Edwards curve name algo_opts="$EASYRSA_CURVE" ;; *) die "gen_req - Unknown algorithm: $EASYRSA_ALGO" esac # Generate request if easyrsa_openssl req -utf8 -new -newkey "$algo_opts" \ -keyout "$key_out_tmp" \ -out "$req_out_tmp" \ ${EASYRSA_NO_PASS:+ "$no_password"} \ ${text:+ -text} \ ${ssl_batch:+ -batch} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} then : # ok else die "Failed to generate request" fi # Move temp-files to target-files mv "$key_out_tmp" "$key_out" || { die "Failed to move key temp-file" } mv "$req_out_tmp" "$req_out" || { rm -f "$key_out" # Also remove the key die "Failed to move req temp-file" } # Success messages notice "\ Private-Key and Public-Certificate-Request files created. Your files are: * req: $req_out * key: $key_out${do_build_full:+ $NL}" return 0 } # => gen_req() # common signing backend sign_req() { crt_type="$1" file_name_base="$2" # Check argument sanity: [ "$file_name_base" ] || user_error "\ Incorrect number of arguments provided to sign-req: expected 2, got $# (see command help for usage)" req_in="$EASYRSA_PKI/reqs/$file_name_base.req" crt_out="$EASYRSA_PKI/issued/$file_name_base.crt" shift 2 # Check for preserve-dn while [ "$1" ]; do case "$1" in preserve*) export EASYRSA_PRESERVE_DN=1 ;; *) warn "Ignoring unknown option '$1'" esac shift done # Cert type must NOT be COMMON [ "$crt_type" = COMMON ] && user_error "\ Invalid certificate type: '$crt_type'" # Request file must exist [ -e "$req_in" ] || user_error "\ No request found for the input: '$file_name_base' Expected to find the request at: * $req_in" # Certificate file must NOT exist [ ! -e "$crt_out" ] || user_error "\ Cannot sign this request for '$file_name_base'. Conflicting certificate exists at: * $crt_out" # Confirm input is a cert req verify_file req "$req_in" || user_error "\ The certificate request file is not in a valid X509 format: * $req_in" # Randomize Serial number if [ "$EASYRSA_RAND_SN" != no ]; then serial="" check_serial="" unset -v serial_is_unique for i in 1 2 3 4 5; do serial="$( easyrsa_random 16 )" || die "sign_req - easyrsa_random" # Check for duplicate serial in CA db if check_serial_unique "$serial" batch; then serial_is_unique=1 break fi done # Check for unique_serial [ "$serial_is_unique" ] || die "\ sign_req - Randomize Serial number failed: $check_serial" # Print random $serial to pki/serial file # for use by SSL config print "$serial" > "$EASYRSA_PKI/serial" || \ die "sign_req - write serial to file" unset -v serial check_serial serial_is_unique fi # When EASYRSA_CP_EXT is defined, # adjust openssl's [default_ca] section: if [ "$EASYRSA_CP_EXT" ]; then # Check for insert-marker in ssl config file if ! grep -q '^#%COPY_EXTS%' "$EASYRSA_SSL_CONF" then die "\ This openssl config file does \ not support option '--copy-ext'. * $EASYRSA_SSL_CONF Please update 'openssl-easyrsa.cnf' \ to the latest Easy-RSA release." fi # Setup & insert the copy_extensions data # keyed by a magic line copy_exts="copy_extensions = copy" # shellcheck disable=SC2016 # vars don't expand '' awkscript=' {if ( match($0, "^#%COPY_EXTS%") ) { while ( getline<"/dev/stdin" ) {print} next } {print} }' # Assign temp-file for confg raw_ssl_cnf_tmp="" easyrsa_mktemp raw_ssl_cnf_tmp || \ die "sign_req - easyrsa_mktemp raw_ssl_cnf_tmp" print "$copy_exts" | \ awk "$awkscript" "$EASYRSA_SSL_CONF" \ > "$raw_ssl_cnf_tmp" || die "\ Writing 'copy_exts' to SSL config temp-file failed" # Use this SSL config for the rest of this function EASYRSA_SSL_CONF="$raw_ssl_cnf_tmp" verbose "sign_req: Using '$copy_exts'" fi # Find or create x509-type file if [ -f "$EASYRSA_EXT_DIR/$crt_type" ]; then # Use the x509-types/$crt_type file x509_type_file="$EASYRSA_EXT_DIR/$crt_type" else # Use a temp file x509_type_tmp="" easyrsa_mktemp x509_type_tmp || \ die "sign_req - easyrsa_mktemp x509_type_tmp" create_x509_type "$crt_type" > "$x509_type_tmp" || \ die "sign_req - create_x509_type $crt_type" x509_type_file="$x509_type_tmp" fi # Find or create x509 COMMON file if [ -f "$EASYRSA_EXT_DIR/COMMON" ]; then # Use the x509-types/COMMON file x509_COMMON_file="$EASYRSA_EXT_DIR/COMMON" else # Use a temp file x509_COMMON_tmp="" easyrsa_mktemp x509_COMMON_tmp || \ die "sign_req - easyrsa_mktemp x509_COMMON_tmp" create_x509_type COMMON > "$x509_COMMON_tmp" || \ die "sign_req - create_x509_type COMMON" x509_COMMON_file="$x509_COMMON_tmp" fi # Support a dynamic CA path length when present: unset -v basicConstraints if [ "$crt_type" = "ca" ] && [ "$EASYRSA_SUBCA_LEN" ] then # Print the last occurence of basicContraints in # x509-types/ca # If basicContraints is not defined then bail # shellcheck disable=SC2016 # vars don't expand '' awkscript='\ /^[[:blank:]]*basicConstraints[[:blank:]]*=/ { bC=$0 } END { if (length(bC) == 0 ) exit 1; print bC }' basicConstraints="$( awk "$awkscript" "$x509_type_file" )" || die "\ basicConstraints is not defined, cannot use 'pathlen'" verbose "sign_req: Using basicConstraints pathlen" fi # Deprecated Netscape extension support case "$EASYRSA_NS_SUPPORT" in [yY][eE][sS]) confirm "Confirm use of Netscape extensions: " yes \ "WARNING: Netscape extensions are DEPRECATED!" # Netscape extension case "$crt_type" in serverClient) ns_cert_type="nsCertType = serverClient" ;; server) ns_cert_type="nsCertType = server" ;; client) ns_cert_type="nsCertType = client" ;; ca) ns_cert_type="nsCertType = sslCA" ;; *) ns_cert_type="nsCertType = $crt_type" esac verbose "sign_req: Using $ns_cert_type" ;; *) # ok No NS support required unset -v ns_cert_type esac # Generate the extensions file for this cert: ext_tmp="" easyrsa_mktemp ext_tmp || \ die "sign_req - easyrsa_mktemp ext_tmp" # Begin output redirect { # Append $cert-type extensions cat "$x509_COMMON_file" "$x509_type_file" # Support a dynamic CA path length when present: if [ "$basicConstraints" ]; then print "$basicConstraints, pathlen:$EASYRSA_SUBCA_LEN" fi # Deprecated Netscape extension support if [ "$ns_cert_type" ]; then print "$ns_cert_type" print "nsComment = \"$EASYRSA_NS_COMMENT\"" fi # Add user SAN from --subject-alt-name if [ "$EASYRSA_EXTRA_EXTS" ]; then print "$EASYRSA_EXTRA_EXTS" else # or default server SAN # If type is server and no subjectAltName was # requested then add one to the extensions file if [ "$crt_type" = 'server' ] || \ [ "$crt_type" = 'serverClient' ]; then # req san or default server SAN san="$(display_san req "$req_in")" if [ "$san" ]; then print "subjectAltName = $san" else default_server_san "$req_in" fi fi fi } > "$ext_tmp" || die "\ Error message: $error_msg Failed to create temp extension file (bad permissions?) at: * $ext_tmp" verbose "sign_req: Generated extensions file OK" # Set valid_period message if [ "$EASYRSA_END_DATE" ]; then valid_period=" until date '$EASYRSA_END_DATE'" else valid_period=" for '$EASYRSA_CERT_EXPIRE' days" fi # Display the request subject in an easy-to-read format # Confirm the user wishes to sign this request # The foriegn_request confirmation is not required # for build_full: if [ "$do_build_full" ]; then unset -v foriegn_request else foriegn_request="\ Please check over the details shown below for accuracy. \ Note that this request has not been cryptographically verified. Please be sure \ it came from a trusted source or that you have verified the request checksum \ with the sender.$NL" fi confirm "Confirm request details: " "yes" "\ You are about to sign the following certificate: ${foriegn_request}Request subject, to be signed as a \ $crt_type certificate ${valid_period}: $(display_dn req "$req_in")" # => confirm end # Assign temp cert file crt_out_tmp="" easyrsa_mktemp crt_out_tmp || \ die "sign_req - easyrsa_mktemp crt_out_tmp" # sign request easyrsa_openssl ca -utf8 -batch \ -in "$req_in" -out "$crt_out_tmp" \ -extfile "$ext_tmp" \ ${EASYRSA_PRESERVE_DN:+ -preserveDN} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_NO_TEXT:+ -notext} \ ${EASYRSA_CERT_EXPIRE:+ -days "$EASYRSA_CERT_EXPIRE"} \ ${EASYRSA_START_DATE:+ -startdate "$EASYRSA_START_DATE"} \ ${EASYRSA_END_DATE:+ -enddate "$EASYRSA_END_DATE"} \ || die "\ Signing failed (openssl output above may have more detail)" verbose "sign_req: signed cert '$file_name_base' OK" mv "$crt_out_tmp" "$crt_out" || \ die "Failed to move temp-file to certificate." # Success messages notice "\ Certificate created at: * $crt_out" return 0 } # => sign_req() # Check serial in db check_serial_unique() { [ "$1" ] || user_error "Serial number required!" case "$1" in (*[!1234567890abcdef]*) user_error "Invalid serial number: '$1'" ;; *) : # ok esac unset -v unique_serial_true # Check for openssl -status of serial number # Always errors out - Do not capture error # unset EASYRSA_SILENT_SSL to capure all output # Do NOT unset check_serial for sign-req error msg check_serial="$( unset -v EASYRSA_SILENT_SSL easyrsa_openssl ca -status "$1" 2>&1 )" || : # Check for duplicate serial in CA db case "$check_serial" in (*"not present in db"*) unique_serial_true=1 verbose "check_serial_unique: unique_serial=true" ;; *) : # Some other response verbose "check_serial_unique: unique_serial=false" esac # In batch mode return result only if [ "$2" = batch ] || [ "$EASYRSA_BATCH" ]; then if [ "$unique_serial_true" ]; then unset -v unique_serial_true return 0 else unset -v unique_serial_true return 1 fi fi # Otherwise, show result to user # and do not return any error code print " check_serial_status RESULT: ======================================== $check_serial ======================================== COMPLETE" } # => check_serial_unique() # common build backend # used to generate+sign in 1 step build_full() { # pull filename base: [ "$2" ] || user_error "\ Error: didn't find a file base name as the first argument. Run easyrsa without commands for usage and commands." crt_type="$1" name="$2" shift 2 req_out="$EASYRSA_PKI/reqs/$name.req" key_out="$EASYRSA_PKI/private/$name.key" crt_out="$EASYRSA_PKI/issued/$name.crt" # function opts support while [ "$1" ]; do case "$1" in nopass) [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; *) warn "Ignoring unknown command option: '$1'" esac shift done # abort on existing req/key/crt files err_exists="\ file already exists. Aborting build to avoid overwriting this file. If you wish to continue, please use a different name. Conflicting file found at: *" [ -e "$req_out" ] && \ user_error "Request $err_exists $req_out" [ -e "$key_out" ] && \ user_error "Key $err_exists $key_out" [ -e "$crt_out" ] && \ user_error "Certificate $err_exists $crt_out" unset -v err_exists # Make inline directory [ -d "$EASYRSA_PKI/inline" ] || \ mkdir -p "$EASYRSA_PKI/inline" || \ die "Failed to create inline directoy." # Confirm over write inline file inline_out="$EASYRSA_PKI/inline/$name.inline" [ -e "$inline_out" ] && \ confirm "Confirm OVER-WRITE existing inline file ? " y "\ Warning! An inline file for name '$name' already exists: * $inline_out" # Set commonName [ "$EASYRSA_REQ_CN" = ChangeMe ] || user_error "\ Option conflict: * '$cmd' does not support setting an external commonName" EASYRSA_REQ_CN="$name" # create request do_build_full=1 gen_req "$name" batch # Sign it error_build_full_cleanup=1 if sign_req "$crt_type" "$name"; then unset -v error_build_full_cleanup do_build_full else die "\ Failed to sign '$name' - \ See error messages above for details." fi # inline it if inline_creds "$name" > "$inline_out"; then notice "\ Inline file created: * $inline_out" else warn "\ INCOMPLETE Inline file created: * $inline_out" fi return 0 } # => build_full() # Print inline data for file_name_base inline_creds () { [ "$1" ] || die "inline_creds - Missing file_name_base" # Source files crt_source="${EASYRSA_PKI}/issued/${1}.crt" key_source="${EASYRSA_PKI}/private/${1}.key" ca_source="$EASYRSA_PKI/ca.crt" incomplete=0 # Generate data if [ -e "$crt_source" ]; then # Get EasyRSA cert type ssl_cert_x509v3_eku "$crt_source" type_data crt_data="\ $(cat "$crt_source") " else # Set EasyRSA cert type to 'undefined' type_data=undefined incomplete=1 crt_data="\ * Paste your user certificate here * " fi if [ -e "$key_source" ]; then key_data="\ $(cat "$key_source") " else incomplete=1 key_data="\ * Paste your private key here * " fi if [ -e "$ca_source" ]; then ca_data="\ $(cat "$ca_source") " else incomplete=1 ca_data="\ * Paste your CA certificate here * " fi # Print data print "\ # Easy-RSA Type: ${type_data} # Name: ${1} $crt_data $key_data $ca_data " # If inline file is incomplete then return error return "$incomplete" } # => inline_creds () # revoke backend revoke() { # pull filename base: [ "$1" ] || user_error "\ Error: didn't find a file base name as the first argument. Run easyrsa without commands for usage and command help." # Assign file_name_base and dust off! file_name_base="$1" shift in_dir="$EASYRSA_PKI" crt_in="$in_dir/issued/${file_name_base}.crt" key_in="$in_dir/private/${file_name_base}.key" req_in="$in_dir/reqs/${file_name_base}.req" creds_in="$in_dir/${file_name_base}.creds" inline_in="$in_dir/inline/${file_name_base}.inline" # Assign possible "crl_reason" if [ "$1" ]; then crl_reason="$1" shift case "$crl_reason" in unspecified) : ;; keyCompromise) : ;; CACompromise) : ;; affiliationChanged) : ;; superseded) : ;; cessationOfOperation) : ;; certificateHold) : ;; *) user_error "Illegal reason: $crl_reason" esac else unset -v crl_reason fi # Enforce syntax if [ "$1" ]; then user_error "Syntax error: $1" fi # referenced cert must exist: [ -e "$crt_in" ] || user_error "\ Unable to revoke as no certificate was found. Certificate was expected at: * $crt_in" # Verify certificate verify_file x509 "$crt_in" || user_error "\ Unable to revoke as the input-file is not a valid certificate. Certificate was expected at: * $crt_in" # Verify request if [ -e "$req_in" ]; then verify_file req "$req_in" || user_error "\ Unable to verify request. The file is not a valid request. Request was expected at: * $req_in" fi # get the serial number of the certificate ssl_cert_serial "$crt_in" cert_serial || \ die "$cmd: Failed to get cert serial number!" # Duplicate cert by serial file dup_dir="$EASYRSA_PKI/certs_by_serial" dup_crt_by_serial="$dup_dir/${cert_serial}.pem" # Set out_dir out_dir="$EASYRSA_PKI/revoked" crt_out="$out_dir/certs_by_serial/${cert_serial}.crt" key_out="$out_dir/private_by_serial/${cert_serial}.key" req_out="$out_dir/reqs_by_serial/${cert_serial}.req" # NEVER over-write a revoked cert, serial must be unique deny_msg="\ Cannot revoke this certificate, a conflicting file exists. *" [ -e "$crt_out" ] && \ user_error "$deny_msg certificate: $crt_out" [ -e "$key_out" ] && \ user_error "$deny_msg private key: $key_out" [ -e "$req_out" ] && \ user_error "$deny_msg request : $req_out" unset -v deny_msg # Check for key and request files unset -v if_exist_key_in if_exist_req_in [ -e "$key_in" ] && if_exist_key_in=" * $key_in" [ -e "$req_in" ] && if_exist_req_in=" * $req_in" # confirm operation by displaying DN: warn "\ This process is destructive! These files will be MOVED to the 'revoked' sub-directory: * $crt_in${if_exist_key_in}${if_exist_req_in} These files will be DELETED: All PKCS files for commonName : $file_name_base The inline credentials files: * $creds_in * $inline_in The duplicate certificate: * $dup_crt_by_serial" confirm " Continue with revocation: " "yes" " Please confirm that you wish to revoke the certificate with the following subject: $(display_dn x509 "$crt_in") serial-number: $cert_serial Reason: ${crl_reason:-None given}" # Revoke certificate easyrsa_openssl ca -utf8 -revoke "$crt_in" \ ${crl_reason:+ -crl_reason "$crl_reason"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ || die "\ Failed to revoke certificate: revocation command failed." # move revoked files # so we can reissue certificates with the same name revoke_move notice "\ * IMPORTANT * Revocation was successful. You must run 'gen-crl' and upload a new CRL to your infrastructure in order to prevent the revoked certificate from being accepted." return 0 } # => revoke() # revoke_move # moves revoked certificates to the 'revoked' folder # allows reissuing certificates with the same name revoke_move() { for target in "$out_dir" \ "$out_dir/certs_by_serial" \ "$out_dir/private_by_serial" \ "$out_dir/reqs_by_serial" do [ -d "$target" ] && continue mkdir -p "$target" || die "Failed to mkdir: $target" done # move crt, key and req file to renewed_then_revoked folders mv "$crt_in" "$crt_out" || die "Failed to move: $crt_in" # only move the key if we have it if [ -e "$key_in" ]; then mv "$key_in" "$key_out" || warn "Failed to move: $key_in" fi # only move the req if we have it if [ -e "$req_in" ]; then mv "$req_in" "$req_out" || warn "Failed to move: $req_in" fi # remove any pkcs files for pkcs in p12 p7b p8 p1; do if [ -e "$in_dir/issued/$file_name_base.$pkcs" ]; then # issued rm "$in_dir/issued/$file_name_base.$pkcs" || warn "Failed to remove: $file_name_base.$pkcs" elif [ -e "$in_dir/private/$file_name_base.$pkcs" ]; then # private rm "$in_dir/private/$file_name_base.$pkcs" || warn "Failed to remove: $file_name_base.$pkcs" else : # ok fi done # remove the duplicate certificate if [ -e "$dup_crt_by_serial" ]; then rm "$dup_crt_by_serial" || warn "\ Failed to remove the duplicate certificate: * $dup_crt_by_serial" fi # remove credentials file if [ -e "$creds_in" ]; then rm "$creds_in" || warn "\ Failed to remove credentials file: * $creds_in" fi # remove inline file if [ -e "$inline_in" ]; then rm "$inline_in" || warn "\ Failed to remove inline file: * $inline_in" fi return 0 } # => revoke_move() # renew backend renew() { # pull filename base: [ "$1" ] || user_error "\ Error: didn't find a file base name as the first argument. Run easyrsa without commands for usage and command help." # Assign file_name_base and dust off! file_name_base="$1" shift # Assign input files in_dir="$EASYRSA_PKI" crt_in="$in_dir/issued/${file_name_base}.crt" key_in="$in_dir/private/${file_name_base}.key" # key_out is used by inline_creds() key_out="$in_dir/private/${file_name_base}.key" req_in="$in_dir/reqs/${file_name_base}.req" creds_in="$in_dir/${file_name_base}.creds" inline_in="$in_dir/inline/${file_name_base}.inline" # Upgrade CA index.txt.attr - unique_subject = no up23_upgrade_ca || \ die "Failed to upgrade CA to support renewal." # deprecate ALL options while [ "$1" ]; do case "$1" in nopass) warn "\ Option 'nopass' is not supported by command 'renew'." ;; *) user_error "Unknown option: $1" esac shift done # Verify certificate if [ -f "$crt_in" ]; then verify_file x509 "$crt_in" || user_error "\ Input file is not a valid certificate: * $crt_in" else user_error "\ Missing certificate file: * $crt_in" fi # Verify request if [ -e "$req_in" ]; then verify_file req "$req_in" || user_error "\ Input file is not a valid request: * $req_in" else user_error "\ Missing request file: * $req_in" fi # get the serial number of the certificate ssl_cert_serial "$crt_in" cert_serial || \ die "$cmd: Failed to get cert serial number!" # Duplicate cert by serial file dup_dir="$EASYRSA_PKI/certs_by_serial" dup_crt_by_serial="$dup_dir/${cert_serial}.pem" # Set out_dir out_dir="$EASYRSA_PKI/renewed" crt_out="$out_dir/issued/${file_name_base}.crt" # NEVER over-write a renewed cert, revoke it first deny_msg="\ Cannot renew this certificate, a conflicting file exists: *" [ -e "$crt_out" ] && \ user_error "$deny_msg certificate: $crt_out" unset -v deny_msg # Make inline directory [ -d "$EASYRSA_PKI/inline" ] || \ mkdir -p "$EASYRSA_PKI/inline" || \ die "Failed to create inline directoy." # Extract certificate usage from old cert ssl_cert_x509v3_eku "$crt_in" cert_type # Use SAN from --san if set else use SAN from old cert if echo "$EASYRSA_EXTRA_EXTS" | grep -q subjectAltName then : # ok - Use current subjectAltName else san="$( easyrsa_openssl x509 -in "$crt_in" -noout -text | sed -n \ "/X509v3 Subject Alternative Name:\ /{n;s/IP Address:/IP:/g;s/ //g;p;}" )" || die "renew - san: easyrsa_openssl subshell" [ "$san" ] && export EASYRSA_EXTRA_EXTS="\ $EASYRSA_EXTRA_EXTS subjectAltName = $san" fi # confirm operation by displaying DN: warn "\ This process is destructive! These files will be MOVED to the 'renewed' sub-directory: * $crt_in These files will be DELETED: All PKCS files for commonName: $file_name_base The inline credentials files: * $creds_in * $inline_in The duplicate certificate: * $dup_crt_by_serial" confirm " Continue with renewal: " "yes" " Please confirm you wish to renew the certificate with the following subject: $(display_dn x509 "$crt_in") serial-number: $cert_serial" # move renewed files # so we can reissue certificate with the same name renew_move error_undo_renew_move=1 # renew certificate if EASYRSA_BATCH=1 sign_req "$cert_type" "$file_name_base" then unset -v error_undo_renew_move else # If renew failed then restore cert. # Otherwise, issue a warning renew_restore_move die "\ Renewal has failed to build a new certificate." fi # inline it # Over write existing because renew is successful if inline_creds "$file_name_base" > "$inline_in" then notice "\ Inline file created: * $inline_in" else warn "\ INCOMPLETE Inline file created: * $inline_in" fi # Success messages notice "\ Renew was successful. * IMPORTANT * Renew has created a new certificate, to replace the old one. To revoke the old certificate, once the new one has been deployed, use command: 'revoke-renewed $file_name_base reason' ('reason' is optional)" return 0 } # => renew() # Restore files on failure to renew renew_restore_move() { unset -v rrm_err error_undo_renew_move # restore crt file to PKI folders if mv "$restore_crt_out" "$restore_crt_in"; then : # ok else warn "Failed to restore: $restore_crt_out" rrm_err=1 fi # messages if [ "$rrm_err" ]; then warn "Failed to restore renewed files." else notice "\ Renew FAILED but files have been successfully restored." fi return 0 } # => renew_restore_move() # renew_move # moves renewed certificates to the 'renewed' folder # allows reissuing certificates with the same name renew_move() { # make sure renewed dirs exist for target in "$out_dir" \ "$out_dir/issued" \ "$out_dir/private" \ "$out_dir/reqs" do [ -d "$target" ] && continue mkdir -p "$target" || die "Failed to mkdir: $target" done # move crt, key and req file to renewed folders # After this point, renew is possible! restore_crt_in="$crt_in" restore_crt_out="$crt_out" mv "$crt_in" "$crt_out" || \ die "Failed to move: $crt_in" # Further file removal is a convenience, only. # remove any pkcs files for pkcs in p12 p7b p8 p1; do # issued rm -f "$in_dir/issued/$file_name_base.$pkcs" # private rm -f "$in_dir/private/$file_name_base.$pkcs" done # remove the duplicate certificate if [ -e "$dup_crt_by_serial" ]; then rm "$dup_crt_by_serial" || warn "\ Failed to remove the duplicate certificate: * $dup_crt_by_serial" fi # remove credentials file if [ -e "$creds_in" ]; then rm "$creds_in" || warn "\ Failed to remove credentials file: * $creds_in" fi # remove inline file if [ -e "$inline_in" ]; then rm "$inline_in" || warn "\ Failed to remove inline file: * $inline_in" fi return 0 } # => renew_move() # revoke-renewed backend revoke_renewed() { # pull filename base: [ "$1" ] || user_error "\ Error: didn't find a file base name as the first argument. Run easyrsa without commands for usage and command help." # Assign file_name_base and dust off! file_name_base="$1" shift in_dir="$EASYRSA_PKI/renewed" crt_in="$in_dir/issued/$file_name_base.crt" key_in="$in_dir/private/$file_name_base.key" req_in="$in_dir/reqs/$file_name_base.req" #creds_in="$EASYRSA_PKI/$file_name_base.creds" # Assign possible "crl_reason" if [ "$1" ]; then crl_reason="$1" shift case "$crl_reason" in unspecified) : ;; keyCompromise) : ;; CACompromise) : ;; affiliationChanged) : ;; superseded) : ;; cessationOfOperation) : ;; certificateHold) : ;; *) user_error "Illegal reason: $crl_reason" esac else unset -v crl_reason fi # Enforce syntax if [ "$1" ]; then user_error "Syntax error: $1" fi # referenced cert must exist: [ -f "$crt_in" ] || user_error "\ Unable to revoke as no renewed certificate was found. Certificate was expected at: * $crt_in" # Verify certificate verify_file x509 "$crt_in" || user_error "\ Unable to revoke as the input-file is not a valid certificate. Certificate was expected at: * $crt_in" # Verify request if [ -e "$req_in" ]; then verify_file req "$req_in" || user_error "\ Unable to verify request. The file is not a valid request. Request was expected at: * $req_in" fi # get the serial number of the certificate ssl_cert_serial "$crt_in" cert_serial || \ die "$cmd: Failed to get cert serial number!" # Duplicate cert by serial file dup_dir="$EASYRSA_PKI/certs_by_serial" dup_crt_by_serial="$dup_dir/${cert_serial}.pem" # output out_dir="$EASYRSA_PKI/revoked" crt_out="$out_dir/certs_by_serial/$cert_serial.crt" key_out="$out_dir/private_by_serial/$cert_serial.key" req_out="$out_dir/reqs_by_serial/$cert_serial.req" # NEVER over-write a revoked cert, serial must be unique deny_msg="\ Cannot revoke this certificate, a conflicting file exists. *" [ -e "$crt_out" ] && \ user_error "$deny_msg certificate: $crt_out" [ -e "$key_out" ] && \ user_error "$deny_msg private key: $key_out" [ -e "$req_out" ] && \ user_error "$deny_msg request : $req_out" unset -v deny_msg # confirm operation by displaying DN: unset -v if_exist_key_in if_exist_req_in [ -e "$key_in" ] && if_exist_key_in=" * $key_in" [ -e "$req_in" ] && if_exist_req_in=" * $req_in" warn "\ This process is destructive! These files will be MOVED to the 'revoked' sub-directory: * $crt_in${if_exist_key_in}${if_exist_req_in}" confirm " Continue with revocation: " "yes" " Please confirm you wish to revoke the renewed certificate with the following subject: $(display_dn x509 "$crt_in") serial-number: $cert_serial Reason: ${crl_reason:-None given}" # Revoke the old (already renewed) certificate easyrsa_openssl ca -utf8 -revoke "$crt_in" \ ${crl_reason:+ -crl_reason "$crl_reason"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} || \ die "\ Failed to revoke renewed certificate: revocation command failed." # move revoked files revoke_renewed_move notice "\ * IMPORTANT * Revocation was successful. You must run 'gen-crl' and upload a new CRL to your infrastructure in order to prevent the revoked certificate from being accepted." return 0 } # => revoke_renewed() # move-renewed-revoked # moves renewed then revoked certificates to the 'revoked' folder revoke_renewed_move() { # make sure revoked dirs exist for target in "$out_dir" \ "$out_dir/certs_by_serial" \ "$out_dir/private_by_serial" \ "$out_dir/reqs_by_serial" do [ -d "$target" ] && continue mkdir -p "$target" || die "Failed to mkdir: $target" done # move crt, key and req file to renewed_then_revoked folders mv "$crt_in" "$crt_out" || die "Failed to move: $crt_in" # only move the key if we have it if [ -e "$key_in" ]; then mv "$key_in" "$key_out" || warn "Failed to move: $key_in" fi # only move the req if we have it if [ -e "$req_in" ]; then mv "$req_in" "$req_out" || warn "Failed to move: $req_in" fi return 0 } # => revoke_renewed_move() # Move renewed certs_by_serial to the new renew layout rewind_renew() { # pull filename base: serial number [ "$1" ] || user_error "\ Error: didn't find a serial number as the first argument. Run easyrsa without commands for usage and command help." # Assign file_name_base and dust off! file_name_base="$1" shift "$#" # No options supported cert_serial="$file_name_base" in_dir="$EASYRSA_PKI/renewed" crt_in="$in_dir/certs_by_serial/${file_name_base}.crt" key_in="$in_dir/private_by_serial/${file_name_base}.key" req_in="$in_dir/reqs_by_serial/${file_name_base}.req" # referenced cert must exist: [ -f "$crt_in" ] || user_error "\ Unable to rewind as no certificate was found. Certificate was expected at: * $crt_in" # Verify certificate verify_file x509 "$crt_in" || user_error "\ Unable to rewind as the input file is not a valid certificate. Certificate was expected at: * $crt_in" # Verify request if [ -e "$req_in" ]; then verify_file req "$req_in" || user_error "\ Unable to verify request. The file is not a valid request. Request was expected at: * $req_in" fi # get the commonName of the certificate via DN crt_cn="$( easyrsa_openssl x509 -in "$crt_in" -noout \ -subject -nameopt utf8,multiline | grep \ '^[[:blank:]]*commonName[[:blank:]]*=[[:blank:]]' )" || die "Failed to find commonName in certificate" crt_cn="${crt_cn#*= }" # Set out_dir out_dir="$EASYRSA_PKI/renewed" crt_out="$out_dir/issued/${crt_cn}.crt" key_out="$out_dir/private/${crt_cn}.key" req_out="$out_dir/reqs/${crt_cn}.req" # Create out_dir for newdir in issued private reqs; do mkdir -p "$out_dir/$newdir" || \ die "Failed to create: $out_dir/$newdir" done # NEVER over-write a renewed cert, revoke it first deny_msg="\ Cannot rewind this certificate, a conflicting file exists. *" [ -e "$crt_out" ] && \ user_error "$deny_msg certificate: $crt_out" [ -e "$key_out" ] && \ user_error "$deny_msg private key: $key_out" [ -e "$req_out" ] && \ user_error "$deny_msg request : $req_out" unset -v deny_msg warn "\ This process is destructive! These files will be MOVED to the 'renewed' sub-directory: * $crt_in * $key_in * $req_in" confirm " Continue with rewind-renew: " "yes" " Please confirm you wish to rewind-renew the certificate with the following subject: $(display_dn x509 "$crt_in") serial-number: $cert_serial " # => confirm end # move crt, key and req file to renewed folders mv "$crt_in" "$crt_out" || die "Failed to move: $crt_in" # only move the key if we have it if [ -e "$key_in" ]; then if mv "$key_in" "$key_out"; then : # ok else # Attempt restore mv -f "$crt_out" "$crt_in" die "Failed to move: $key_in" fi fi # only move the req if we have it if [ -e "$req_in" ]; then if mv "$req_in" "$req_out"; then : # ok else # Attempt restore mv -f "$crt_out" "$crt_in" mv -f "$key_out" "$key_in" die "Failed to move: $req_in" fi fi # Success message notice "\ Rewind is successful. Common Name : $crt_cn Serial number: $cert_serial To revoke use: 'revoke-renewed $crt_cn'" } # => rewind_renew() # rebuild backend rebuild() { # pull filename base: [ "$1" ] || user_error "\ Error: didn't find a file base name as the first argument. Run easyrsa without commands for usage and command help." # Assign file_name_base and dust off! file_name_base="$1" shift in_dir="$EASYRSA_PKI" crt_in="$in_dir/issued/${file_name_base}.crt" key_in="$in_dir/private/${file_name_base}.key" req_in="$in_dir/reqs/${file_name_base}.req" creds_in="$in_dir/${file_name_base}.creds" inline_in="$in_dir/inline/${file_name_base}.inline" # Upgrade CA index.txt.attr - unique_subject = no up23_upgrade_ca || \ die "Failed to upgrade CA to support renewal." # Set 'nopass' while [ "$1" ]; do case "$1" in nopass) [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; *) user_error "Unknown option: $1" esac shift done # referenced cert must exist: [ -f "$crt_in" ] || user_error "\ Unable to rebuild as no certificate was found. Certificate was expected at: * $crt_in" # Verify certificate verify_file x509 "$crt_in" || user_error "\ Unable to rebuild as the input file is not a valid certificate. Certificate was expected at: * $crt_in" # Verify request if [ -e "$req_in" ]; then verify_file req "$req_in" || user_error "\ Unable to verify request. The file is not a valid request. Request was expected at: * $req_in" fi # get the serial number of the certificate ssl_cert_serial "$crt_in" cert_serial || \ die "$cmd: Failed to get cert serial number!" # Duplicate cert by serial file dup_dir="$EASYRSA_PKI/certs_by_serial" dup_crt_by_serial="$dup_dir/${cert_serial}.pem" # Set out_dir out_dir="$EASYRSA_PKI/renewed" crt_out="$out_dir/issued/${file_name_base}.crt" key_out="$out_dir/private/${file_name_base}.key" req_out="$out_dir/reqs/${file_name_base}.req" # NEVER over-write a renewed cert, revoke it first deny_msg="\ Cannot rebuild this certificate, a conflicting file exists. *" [ -e "$crt_out" ] && \ user_error "$deny_msg certificate: $crt_out" [ -e "$key_out" ] && \ user_error "$deny_msg private key: $key_out" [ -e "$req_out" ] && \ user_error "$deny_msg request : $req_out" unset -v deny_msg # Extract certificate usage from old cert cert_ext_key_usage="$( easyrsa_openssl x509 -in "$crt_in" -noout -text | sed -n "/X509v3 Extended Key Usage:/{n;s/^ *//g;p;}" )" case "$cert_ext_key_usage" in "TLS Web Client Authentication") cert_type=client ;; "TLS Web Server Authentication") cert_type=server ;; "TLS Web Server Auth"*", TLS Web Client Auth"*) cert_type=serverClient ;; *) die "Unknown key usage: $cert_ext_key_usage" esac # Use SAN from --subject-alt-name, if set # else use SAN from old cert if echo "$EASYRSA_EXTRA_EXTS" | grep -q subjectAltName then : # ok - Use current subjectAltName else san="$( easyrsa_openssl x509 -in "$crt_in" -noout -text | sed -n \ "/X509v3 Subject Alternative Name:/{n;s/IP Address:/IP:/g;s/ //g;p;}" )" [ "$san" ] && export EASYRSA_EXTRA_EXTS="\ $EASYRSA_EXTRA_EXTS subjectAltName = $san" fi # confirm operation by displaying DN: unset -v if_exist_key_in if_exist_req_in [ -e "$key_in" ] && if_exist_key_in=" * $key_in" [ -e "$req_in" ] && if_exist_req_in=" * $req_in" warn "\ This process is destructive! These files will be MOVED to the 'renewed' sub-directory: * $crt_in${if_exist_key_in}${if_exist_req_in} These files will be DELETED: All PKCS files for commonName : $file_name_base The inline credentials files: * $creds_in * $inline_in The duplicate certificate: * $dup_crt_by_serial IMPORTANT: The new key will${EASYRSA_NO_PASS:+ NOT} \ be password protected." confirm " Continue with rebuild: " "yes" " Please confirm you wish to renew the certificate with the following subject: $(display_dn x509 "$crt_in") serial-number: $cert_serial" # move renewed files so we can reissue # certificate with the same name rebuild_move error_undo_rebuild_move=1 # rebuild certificate if EASYRSA_BATCH=1 build_full "$cert_type" "$file_name_base" then unset -v error_undo_rebuild_move else # If rebuild failed then restore cert, key and req. # Otherwise, issue a warning. If *restore* fails # then at least the file-names are not serial-numbers rebuild_restore_move die "\ Rebuild has failed to build a new certificate/key pair." fi # Success messages notice "Rebuild was successful. * IMPORTANT * Rebuild has created a new certificate and key, to replace both old files. To revoke the old certificate, once the new one has been deployed, use command: 'revoke-renewed $file_name_base reason' ('reason' is optional)" return 0 } # => rebuild() # Restore files on failure to rebuild rebuild_restore_move() { unset -v rrm_err error_undo_renew_move # restore crt, key and req file to PKI folders if mv "$restore_crt_out" "$restore_crt_in"; then : # ok else warn "Failed to restore: $restore_crt_out" rrm_err=1 fi # only restore the key if we have it if [ -e "$restore_key_out" ]; then if mv "$restore_key_out" "$restore_key_in"; then : # ok else warn "Failed to restore: $restore_key_out" rrm_err=1 fi fi # only restore the req if we have it if [ -e "$restore_req_out" ]; then if mv "$restore_req_out" "$restore_req_in"; then : # ok else warn "Failed to restore: $restore_req_out" rrm_err=1 fi fi # messages if [ "$rrm_err" ]; then warn "Failed to restore renewed files." else notice "\ Rebuild FAILED but files have been successfully restored." fi return 0 } # => rebuild_restore_move() # rebuild_move # moves renewed certificates to the 'renewed' folder # allows reissuing certificates with the same name rebuild_move() { # make sure renewed dirs exist for target in "$out_dir" \ "$out_dir/issued" \ "$out_dir/private" \ "$out_dir/reqs" do [ -d "$target" ] && continue mkdir -p "$target" || die "Failed to mkdir: $target" done # move crt, key and req file to renewed folders restore_crt_in="$crt_in" restore_crt_out="$crt_out" mv "$crt_in" "$crt_out" || die "Failed to move: $crt_in" # only move the key if we have it restore_key_in="$key_in" restore_key_out="$key_out" if [ -e "$key_in" ]; then mv "$key_in" "$key_out" || warn "Failed to move: $key_in" fi # only move the req if we have it restore_req_in="$req_in" restore_req_out="$req_out" if [ -e "$req_in" ]; then mv "$req_in" "$req_out" || warn "Failed to move: $req_in" fi # remove any pkcs files for pkcs in p12 p7b p8 p1; do if [ -e "$in_dir/issued/$file_name_base.$pkcs" ]; then # issued rm "$in_dir/issued/$file_name_base.$pkcs" || warn "Failed to remove: $file_name_base.$pkcs" elif [ -e "$in_dir/private/$file_name_base.$pkcs" ]; then # private rm "$in_dir/private/$file_name_base.$pkcs" || warn "Failed to remove: $file_name_base.$pkcs" else : # ok fi done # remove the duplicate certificate if [ -e "$dup_crt_by_serial" ]; then rm "$dup_crt_by_serial" || warn "\ Failed to remove the duplicate certificate: * $dup_crt_by_serial" fi # remove credentials file if [ -e "$creds_in" ]; then rm "$creds_in" || warn "\ Failed to remove credentials file: * $creds_in" fi # remove inline file if [ -e "$inline_in" ]; then rm "$inline_in" || warn "\ Failed to remove inline file: * $inline_in" fi return 0 } # => rebuild_move() # gen-crl backend gen_crl() { out_file="$EASYRSA_PKI/crl.pem" out_file_tmp="" easyrsa_mktemp out_file_tmp || \ die "gen_crl - easyrsa_mktemp out_file_tmp" if [ -r "$out_file" ]; then cp -p "$out_file" "$out_file_tmp" || \ warn "Failed to preserve CRL file permissions." fi easyrsa_openssl ca -utf8 -gencrl -out "$out_file_tmp" \ ${EASYRSA_CRL_DAYS:+ -days "$EASYRSA_CRL_DAYS"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} || \ die "CRL Generation failed." mv ${EASYRSA_BATCH:+ -f} "$out_file_tmp" "$out_file" || \ die "Failed to update CRL file." notice "\ An updated CRL has been created: * $out_file" return 0 } # => gen_crl() # import-req backend import_req() { # pull passed paths in_req="$1" short_name="$2" out_req="$EASYRSA_PKI/reqs/$2.req" [ "$short_name" ] || user_error "\ Unable to import: incorrect command syntax. Run easyrsa without commands for usage and command help." # Request file must exist [ -e "$in_req" ] || user_error "\ No request found for the input: '$2' Expected to find the request at: * $in_req" verify_file req "$in_req" || user_error "\ The certificate request file is not in a valid X509 format: * $req_in" # destination must not exist [ -e "$out_req" ] && user_error "\ Please choose a different name for your imported request file. Conflicting file already exists at: * $out_req" # now import it cp "$in_req" "$out_req" notice "\ Request successfully imported with short-name: $short_name This request is now ready to be signed." return 0 } # => import_req() # export pkcs#12, pkcs#7, pkcs#8 or pkcs#1 export_pkcs() { pkcs_type="$1" shift [ "$1" ] || user_error "\ Unable to export '$pkcs_type': incorrect command syntax. Run easyrsa without commands for usage and command help." file_name_base="$1" shift crt_in="$EASYRSA_PKI/issued/$file_name_base.crt" key_in="$EASYRSA_PKI/private/$file_name_base.key" crt_ca="$EASYRSA_PKI/ca.crt" # opts support cipher=-aes256 want_ca=1 want_key=1 unset -v nokeys friendly_name while [ "$1" ]; do case "$1" in noca) want_ca="" ;; nokey) want_key="" # Undocumented OpenSSL feature: option # -nokeys will ignore missing -inkey file # No doubt, the reason for the extra -inkey nokeys=-nokeys ;; nopass) [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; usefn) friendly_name="$file_name_base" ;; *) warn "Ignoring unknown command option: '$1'" esac shift done # Required options - PKCS, rhymes with mess case "$pkcs_type" in p12|p7) : # ok ;; p8|p1) want_key=1 ;; *) die "Unknown PKCS type: $pkcs_type" esac # Check for CA, if required if [ "$want_ca" ]; then case "$pkcs_type" in p12|p7) # verify_ca_init() here, otherwise not required if verify_ca_init test; then : # ok else warn "\ Missing CA Certificate, expected at: * $crt_ca" confirm " Continue without CA Certificate (EG: option 'noca') ? " yes " Your PKI does not include a CA Certificate. You can export your User Certificate to a $pkcs_type file but the CA Certificate will not be included." # --batch mode does not allow # on-the-fly command changes if [ "$EASYRSA_BATCH" ]; then die "export-$pkcs_type: Missing CA" fi want_ca="" fi ;; p8|p1) : # Not required ;; *) die "Unknown PKCS type: $pkcs_type" esac fi # Check for key, if required if [ "$want_key" ]; then if [ -e "$key_in" ]; then : #ok else case "$pkcs_type" in p12) warn "\ Missing Private Key, expected at: * $key_in" confirm " Continue without Private Key (EG: option 'nokey') ? " yes " Your PKI does not include a Private Key for '$file_name_base'. You can export your User Certificate to a '$pkcs_type' file but the Private Key will not be included." # --batch mode does not allow # on-the-fly command changes if [ "$EASYRSA_BATCH" ]; then die "export-$pkcs_type: Missing key" fi nokeys=-nokeys ;; p8|p1) user_error "\ Missing Private Key, expected at: * $key_in" ;; p7) : # Not required ;; *) die "Unknown PKCS type: $pkcs_type" esac fi fi # Check for certificate, if required if [ -e "$crt_in" ]; then : # ok else case "$pkcs_type" in p12|p7) user_error "\ Missing User Certificate, expected at: * $crt_in" ;; p8|p1) : # Not required ;; *) die "Unknown PKCS type: $pkcs_type" esac fi # For 'nopass' PKCS requires an explicit empty password if [ "$EASYRSA_NO_PASS" ]; then EASYRSA_PASSIN=pass: EASYRSA_PASSOUT=pass: unset -v cipher # pkcs#1 only fi # Complete export case "$pkcs_type" in p12) pkcs_out="$EASYRSA_PKI/private/$file_name_base.p12" # export the p12: easyrsa_openssl pkcs12 -export \ -in "$crt_in" \ -out "$pkcs_out" \ ${nokeys} \ -inkey "$key_in" \ ${want_ca:+ -certfile "$crt_ca"} \ ${friendly_name:+ -name "$friendly_name"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \ || die "Failed to export PKCS#12" ;; p7) pkcs_out="$EASYRSA_PKI/issued/$file_name_base.p7b" # export the p7: easyrsa_openssl crl2pkcs7 -nocrl \ -certfile "$crt_in" \ -out "$pkcs_out" \ ${want_ca:+ -certfile "$crt_ca"} \ || die "Failed to export PKCS#7" ;; p8) pkcs_out="$EASYRSA_PKI/private/$file_name_base.p8" # export the p8: easyrsa_openssl pkcs8 -topk8 \ -in "$key_in" \ -out "$pkcs_out" \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \ || die "Failed to export PKCS#8" ;; p1) pkcs_out="$EASYRSA_PKI/private/$file_name_base.p1" # OpenSSLv3 requires -traditional for PKCS#1 # Otherwise, OpenSSLv3 outputs PKCS#8 [ "$verify_ssl_lib_ok" ] || \ die "export_pkcs.p1: verify_ssl_lib_ok FAIL" if [ "$openssl_v3" ]; then traditional=-traditional else unset -v traditional fi # export the p1: easyrsa_openssl rsa \ -in "$key_in" \ -out "$pkcs_out" \ ${traditional} \ ${cipher} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \ || die "Failed to export PKCS#1" ;; *) die "Unknown PKCS type: $pkcs_type" esac notice "\ Successful export of $pkcs_type file. Your exported file is at: * $pkcs_out" return 0 } # => export_pkcs() # set-pass backend legacy set_pass_legacy() { # key type, supplied internally # from frontend command call (rsa/ec) key_type="$1" shift [ "$1" ] || user_error "\ Unable to set password: incorrect command syntax. Run easyrsa without commands for usage and command help." # values supplied by the user: raw_file="$1" shift file="$EASYRSA_PKI/private/${raw_file}.key" # parse command options cipher="-aes256" unset -v nopass while [ "$1" ]; do case "$1" in nopass) [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; file) file="$raw_file" ;; *) warn "Ignoring unknown command option: '$1'" esac shift done # If nopass then do not encrypt else encrypt with password. if [ "$EASYRSA_NO_PASS" ]; then unset -v cipher fi [ -e "$file" ] || user_error "\ Missing private key: expected to find the private key file at: * $file" notice "\ If the key is encrypted then you must supply the current password. ${cipher:+You will then enter a new password for this key.$NL}" # Set password out_key_tmp="" easyrsa_mktemp out_key_tmp || \ die "set_pass_legacy - easyrsa_mktemp out_key_tmp" easyrsa_openssl "$key_type" -in "$file" -out "$out_key_tmp" \ ${cipher:+ "$cipher"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} || die "\ Failed to change the private key passphrase. See above for possible openssl error messages." # Move old key-file out of the way mv "$file" "${file}.tmp" || \ die "Failed to move the old-key file." # Move new key-file into place if mv "$out_key_tmp" "$file"; then rm -f "${file}.tmp" else mv -f "${file}.tmp" "$file" die "Failed to update the private key file." fi notice "Key passphrase successfully changed" return 0 } # => set_pass_legacy() # set-pass backend set_pass() { # values supplied by the user: raw_file="$1" file="$EASYRSA_PKI/private/$raw_file.key" if [ "$raw_file" ]; then shift else user_error "\ Missing argument: no name/file supplied." fi # parse command options cipher="-aes256" while [ "$1" ]; do case "$1" in nopass) [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; file) file="$raw_file" ;; *) warn "Ignoring unknown command option: '$1'" esac shift done # If nopass then do not encrypt else encrypt with password. if [ "$EASYRSA_NO_PASS" ]; then unset -v cipher fi [ -e "$file" ] || user_error "\ Missing private key: expected to find the private key file at: * $file" notice "\ If the key is encrypted then you must supply the current password. ${cipher:+You will then enter a new password for this key.$NL}" # Set password out_key_tmp="" easyrsa_mktemp out_key_tmp || \ die "set_pass - easyrsa_mktemp out_key_tmp" easyrsa_openssl pkey -in "$file" -out "$out_key_tmp" \ ${cipher:+ "$cipher"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} || \ die "Failed to change the private key passphrase." # Move old key-file out of the way mv "$file" "${file}.tmp" || \ die "Failed to move the old-key file." # Move new key-file into place if mv "$out_key_tmp" "$file"; then rm -f "${file}.tmp" else mv -f "${file}.tmp" "$file" die "Failed to update the private key file." fi key_update=changed [ "$EASYRSA_NO_PASS" ] && key_update=removed notice "Key passphrase successfully $key_update" } # => set_pass() # update-db backend update_db() { easyrsa_openssl ca -utf8 -updatedb \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} || \ die "Failed to perform update-db." } # => update_db() # Display subjectAltName display_san() { [ "$#" = 2 ] || die "\ display_san - input error" format="$1" path="$2" shift 2 if echo "$EASYRSA_EXTRA_EXTS" | grep -q subjectAltName; then # Print user defined SAN print "$(\ echo "$EASYRSA_EXTRA_EXTS" | grep subjectAltName | \ sed 's/^[[:space:]]*subjectAltName[[:space:]]*=[[:space:]]*//' )" else # Generate a SAN san="$( x509v3san='X509v3 Subject Alternative Name:' easyrsa_openssl "$format" -in "$path" -noout -text | sed -n \ "/${x509v3san}/{n;s/ //g;s/IPAddress:/IP:/g;s/RegisteredID/RID/;p;}" )" # Print auto SAN [ "$san" ] && print "$san" fi } # => display_san() # display cert DN info on a req/X509, passed by full pathname display_dn() { [ "$#" = 2 ] || die "\ display_dn - input error" format="$1" path="$2" shift 2 # Display DN name_opts="utf8,sep_multiline,space_eq,lname,align" print "$( easyrsa_openssl "$format" -in "$path" -noout -subject \ -nameopt "$name_opts" )" # Display SAN, if present san="$(display_san "$format" "$path")" if [ "$san" ]; then print "" print "X509v3 Subject Alternative Name:" print " $san" fi } # => display_dn() # generate default SAN from req/X509, passed by full pathname default_server_san() { [ "$#" = 1 ] || die "\ default_server_san - input error" path="$1" shift # Command line support for if [ -e "$path" ]; then : # ok else path="${EASYRSA_PKI}/reqs/${path}.req" [ -e "$path" ] || \ user_error "Missing file: $path" fi # Extract CN from DN cn="$( easyrsa_openssl req -in "$path" -noout -subject \ -nameopt sep_multiline | awk -F'=' '/^ *CN=/{print $2}' )" # See: https://github.com/OpenVPN/easy-rsa/issues/576 # Select default SAN if echo "$cn" | grep -q \ -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' then print "subjectAltName = IP:$cn" else print "subjectAltName = DNS:$cn" fi } # => default_server_san() # Verify certificate against CA verify_cert() { # pull filename base: [ "$1" ] || user_error "\ Error: didn't find a as the first argument. Run easyrsa without commands for usage and command help." # Assign file_name_base and dust off! file_name_base="$1" shift # function opts support while [ "$1" ]; do case "$1" in # batch flag, return status [0/1] to calling # program. Otherwise, exit 0 on completion. batch) EASYRSA_BATCH=1 ;; *) warn "Ignoring unknown command option: '$1'" esac shift done in_dir="$EASYRSA_PKI" ca_crt="$in_dir/ca.crt" crt_in="$in_dir/issued/$file_name_base.crt" # Cert file must exist [ -e "$crt_in" ] || user_error "\ No certificate found for the input: '$crt_in'" # Verify file is a valid cert verify_file x509 "$crt_in" || user_error "\ Input is not a valid certificate: $crt_in" # Silent SSL or not if [ "$EASYRSA_SILENT_SSL" ]; then # Test SSL out # openssl direct call because error is expected if OPENSSL_CONF=/dev/null "$EASYRSA_OPENSSL" verify \ -CAfile "$ca_crt" "$crt_in" 1>/dev/null then verify_cert_ok=1 else unset -v verify_cert_ok fi else if OPENSSL_CONF=/dev/null \ "$EASYRSA_OPENSSL" verify \ -CAfile "$ca_crt" "$crt_in" then verify_cert_ok=1 else unset -v verify_cert_ok fi fi # Return cert status if [ "$verify_cert_ok" ]; then notice "\ Certificate name: $file_name_base Verfication status: GOOD" else notice "\ Certificate name: $file_name_base Verfication status: FAILED" # Exit with error (batch mode) if [ "$EASYRSA_BATCH" ]; then # exit with error at cleanup easyrsa_exit_with_error=1 # Return error for internal callers return 1 fi fi } # => verify_cert() # verify a file seems to be a valid req/X509 verify_file() { format="$1" path="$2" easyrsa_openssl "$format" -in "$path" -noout 2>/dev/null } # => verify_file() # show-* command backend # Prints req/cert details in a readable format show() { type="$1" name="$2" in_file="" format="" [ "$name" ] || user_error "\ Missing expected argument. Run easyrsa without commands for usage help." shift 2 # opts support type_opts="-${type}opt" out_opts="no_pubkey,no_sigdump" name_opts="utf8,sep_multiline,space_eq,lname,align" while [ "$1" ]; do case "$1" in full) out_opts= ;; *) warn "Ignoring unknown command option: '$1'" esac shift done # Determine cert/req type (v2) case "$type" in cert) in_file="$EASYRSA_PKI/issued/$name.crt" format="x509" ;; req) in_file="$EASYRSA_PKI/reqs/$name.req" format="req" ;; crl) in_file="$EASYRSA_PKI/$name.pem" format="crl" unset -v type_opts out_opts name_opts ;; *) die "Unrecognised type: $type" esac # Verify file exists and is of the correct type [ -e "$in_file" ] || user_error "\ No such '$type' type file with a of '$name'. Expected to find this file at: * $in_file" verify_file "$format" "$in_file" || user_error "\ This file is not a valid $type file: * $in_file" notice "\ Showing '$type' details for: '$name' This file is stored at: * $in_file${NL}" easyrsa_openssl "$format" -in "$in_file" -noout -text \ ${type_opts:+ "$type_opts" "$out_opts"} \ ${name_opts:+ -nameopt "$name_opts"} || \ die "OpenSSL failure to process the input" } # => show() # show-ca command backend # Prints CA cert details in a readable format show_ca() { # opts support out_opts="no_pubkey,no_sigdump" name_opts="utf8,sep_multiline,space_eq,lname,align" while [ "$1" ]; do case "$1" in full) out_opts= ;; *) warn "Ignoring unknown command option: '$1'" esac shift done in_file="$EASYRSA_PKI/ca.crt" format="x509" # Verify file exists and is of the correct type [ -e "$in_file" ] || user_error "\ No such $type file with a basename of '$name' is present. Expected to find this file at: $in_file" verify_file "$format" "$in_file" || user_error "\ This file is not a valid $type file: $in_file" notice "\ Showing details for CA certificate, at: * $in_file${NL}" easyrsa_openssl "$format" -in "$in_file" -noout -text \ -nameopt "$name_opts" -certopt "$out_opts" || \ die "OpenSSL failure to process the input" } # => show_ca() # Certificate X509v3 Extended Key Usage ssl_cert_x509v3_eku() { [ "$1" ] || die "ssl_cert_x509v3_eku - Missing input" # check input file name if [ -e "$1" ]; then __crt="$1" else __crt="${EASYRSA_PKI}/issued/${1}.crt" [ -e "$__crt" ] || \ die "ssl_cert_x509v3_eku - Missing cert '$__crt'" fi # Set output variable __var="$2" shift "$#" # required variables __pattern="X509v3 Extended Key Usage:" __cli="TLS Web Client Authentication" __srv="TLS Web Server Authentication" __srv_cli="${__srv}, ${__cli}" # Extract certificate usage from old cert __eku="$( easyrsa_openssl x509 -in "${__crt}" -noout -text | \ sed -n "/${__pattern}/{n;s/^ *//g;p;}" )" case "$__eku" in "$__cli") __type=client ;; "$__srv") __type=server ;; "$__srv_cli") __type=serverClient ;; *) die "Unknown key usage: $__eku" esac # Set variable to return if [ "$__var" ]; then force_set_var "$__var" "$__type" else information "${NL}* EasyRSA Certificate type: $__type" fi unset -v __crt __var __pattern __eku __type } # => ssl_cert_x509v3_eku() # get the serial number of the certificate -> serial=XXXX ssl_cert_serial() { [ "$#" = 2 ] || die "ssl_cert_serial - input error" [ -f "$1" ] || die "ssl_cert_serial - missing cert" fn_ssl_out="$( easyrsa_openssl x509 -in "$1" -noout -serial )" || die "ssl_cert_serial - failed: -serial" # remove the serial= part -> we only need the XXXX part fn_ssl_out="${fn_ssl_out##*=}" force_set_var "$2" "$fn_ssl_out" || \ die "ssl_cert_serial - failed to set var '$*'" unset -v fn_ssl_out } # => ssl_cert_serial() # Get certificate start date ssl_cert_not_before_date() { verbose "DEPRECATED: ssl_cert_not_before_date()" [ "$#" = 2 ] || die "\ ssl_cert_not_before_date - input error" [ -f "$1" ] || die "\ ssl_cert_not_before_date - missing cert" fn_ssl_out="$( easyrsa_openssl x509 -in "$1" -noout -startdate )" || die "\ ssl_cert_not_before_date - failed: -startdate" fn_ssl_out="${fn_ssl_out#*=}" force_set_var "$2" "$fn_ssl_out" || die "\ ssl_cert_not_before_date - failed to set var '$*'" unset -v fn_ssl_out } # => ssl_cert_not_before_date() # Get certificate end date ssl_cert_not_after_date() { verbose "DEPRECATED: ssl_cert_not_after_date()" [ "$#" = 2 ] || die "\ ssl_cert_not_after_date - input error" [ -f "$1" ] || die "\ ssl_cert_not_after_date - missing cert" fn_ssl_out="$( easyrsa_openssl x509 -in "$1" -noout -enddate )" || die "\ ssl_cert_not_after_date - failed: -enddate" fn_ssl_out="${fn_ssl_out#*=}" force_set_var "$2" "$fn_ssl_out" || die "\ ssl_cert_not_after_date - failed to set var '$*'" unset -v fn_ssl_out } # => ssl_cert_not_after_date() # SSL -- v3 -- startdate iso_8601 iso_8601_cert_startdate() { verbose "NEW: iso_8601_cert_startdate" [ "$#" = 2 ] || die "\ iso_8601_cert_startdate: input error" [ -f "$1" ] || die "\ iso_8601_cert_startdate: missing cert" # On error return, let the caller decide what to do if fn_ssl_out="$( easyrsa_openssl x509 -in "$1" -noout \ -startdate -dateopt iso_8601 )" then : # ok else # The caller MUST assess this error verbose "\ iso_8601_cert_startdate: GENERATED ERROR" return 1 fi fn_ssl_out="${fn_ssl_out#*=}" force_set_var "$2" "$fn_ssl_out" || die "\ iso_8601_cert_startdate: failed to set var '$*'" unset -v fn_ssl_out } # => iso_8601_cert_startdate() # SSL -- v3 -- enddate iso_8601 iso_8601_cert_enddate() { verbose "NEW: iso_8601_cert_enddate" [ "$#" = 2 ] || die "\ iso_8601_cert_enddate: input error" [ -f "$1" ] || die "\ iso_8601_cert_enddate: missing cert" # On error return, let the caller decide what to do if fn_ssl_out="$( easyrsa_openssl x509 -in "$1" -noout \ -enddate -dateopt iso_8601 )" then : # ok else # The caller MUST assess this error verbose "\ iso_8601_cert_enddate: GENERATED ERROR" return 1 fi fn_ssl_out="${fn_ssl_out#*=}" force_set_var "$2" "$fn_ssl_out" || die "\ iso_8601_cert_enddate: failed to set var '$*'" unset -v fn_ssl_out } # => iso_8601_cert_enddate() # iso_8601_timestamp_to_seconds since epoch iso_8601_timestamp_to_seconds() { verbose "NEW: iso_8601_timestamp_to_seconds" # check input [ "$#" = 2 ] || die "\ iso_8601_timestamp_to_seconds: input error" in_date="$1" verbose "\ NEW: iso_8601_timestamp_to_seconds: in_date=$in_date" # Consume $in_date string yyyy="${in_date%%-*}" # When yyyy is only two digits prepend century if [ "${#yyyy}" = 2 ]; then yyyy="${yyyy#0}" if [ "$yyyy" -lt 70 ]; then if [ "${#yyyy}" = 2 ]; then yyyy="20${yyyy}" else yyyy="200${yyyy}" fi else yyyy="19${yyyy}" fi fi verbose "\ NEW: iso_8601_timestamp_to_seconds: yyyy: $yyyy" # yyyy must be four digits now # Caller MUST assess this error if [ "${#yyyy}" = 4 ]; then : # ok else verbose "\ NEW: iso_8601_timestamp_to_seconds: GENERATED ERROR (yyyy=$yyyy)" return 1 fi # Leap years leap_years="$(( (yyyy - 1970 + 2 ) / 4 ))" is_leap_year="$(( (yyyy - 1970 + 2 ) % 4 ))" if [ "$is_leap_year" = 0 ]; then leap_years="$(( leap_years - 1 ))" leap_day=1 verbose "\ NEW: iso_8601_timestamp_to_seconds: is_leap_year=TRUE" else leap_day=0 verbose "\ NEW: iso_8601_timestamp_to_seconds: is_leap_year=FALSE" fi unset -v is_leap_year in_date="${in_date#*-}" mm="${in_date%%-*}" in_date="${in_date#*-}" dd="${in_date%% *}" in_date="${in_date#* }" HH="${in_date%%:*}" in_date="${in_date#*:}" MM="${in_date%%:*}" in_date="${in_date#*:}" SS="${in_date%?}" in_date="${in_date#??}" TZ="$in_date" unset -v in_date # Check that TZ is a single character if [ "${#TZ}" = 1 ]; then : # ok else # Caller MUST assess this error verbose "\ NEW: iso_8601_timestamp_to_seconds: GENERATED ERROR (TZ=$TZ)" return 1 fi # number of days per month case "$mm" in 01) mdays="$(( 0 ))" ;; 02) mdays="$(( 31 ))" ;; 03) mdays="$(( 31+28+leap_day ))" ;; 04) mdays="$(( 31+28+leap_day+31 ))" ;; 05) mdays="$(( 31+28+leap_day+31+30 ))" ;; 06) mdays="$(( 31+28+leap_day+31+30+31 ))" ;; 07) mdays="$(( 31+28+leap_day+31+30+31+30 ))" ;; 08) mdays="$(( 31+28+leap_day+31+30+31+30+31 ))" ;; 09) mdays="$(( 31+28+leap_day+31+30+31+30+31+31 ))" ;; 10) mdays="$(( 31+28+leap_day+31+30+31+30+31+31+30 ))" ;; 11) mdays="$(( 31+28+leap_day+31+30+31+30+31+31+30+31 ))" ;; 12) mdays="$(( 31+28+leap_day+31+30+31+30+31+31+30+31+30 ))" ;; # This means the input date was not iso_8601 *) # Caller MUST assess this error verbose "\ NEW: iso_8601_timestamp_to_seconds: GENERATED ERROR (mm=$mm)" return 1 esac # Remove leading ZERO. eg: SS = 09 [ "$yyyy" = "${yyyy#0}" ] || die "Leading zero: yyyy: $yyyy" mm="${mm#0}" dd="${dd#0}" HH="${HH#0}" MM="${MM#0}" SS="${SS#0}" # Calculate seconds since epoch out_seconds="$(( (( yyyy - 1970 ) * ( 60 * 60 * 24 * 365 )) + (( leap_years ) * ( 60 * 60 * 24 )) + (( mdays ) * ( 60 * 60 * 24 )) + (( dd - 1 ) * ( 60 * 60 * 24 )) + (( HH ) * ( 60 * 60 )) + (( MM ) * ( 60 )) + SS ))" || die "\ iso_8601_timestamp_to_seconds: out_seconds=$out_seconds" # Return out_seconds force_set_var "$2" "$out_seconds" || die "\ iso_8601_timestamp_to_seconds: \ - force_set_var - $2 - $out_seconds" unset -v in_date out_seconds leap_years \ yyyy mm dd HH MM SS TZ } # => iso_8601_timestamp_to_seconds() # Number of days from NOW@today as timestamp seconds days_to_timestamp_s() { verbose "REQUIRED: days_to_timestamp_s: uses date" # check input [ "$#" = 2 ] || die "\ days_to_timestamp_s: input error" in_days="$1" in_seconds="$(( in_days * 60 * 60 * 24 ))" # There are NO OS dependencies for this use of date # OS dependencies # Linux and Windows # date.exe does not allow +%s as input # MacPorts GNU date if timestamp_s="$( date +%s 2>/dev/null )" then : # ok # Darwin, BSD elif timestamp_s="$( date +%s 2>/dev/null )" then : # ok # busybox elif timestamp_s="$( busybox date +%s 2>/dev/null )" then : # ok # Something else else die "\ days_to_timestamp_s: 'date +%s' failed" fi # Add period timestamp_s="$(( timestamp_s + in_seconds ))" # Return timestamp_s force_set_var "$2" "$timestamp_s" || die "\ days_to_timestamp_s: force_set_var - $2 - $timestamp_s" unset -v in_days in_seconds timestamp_s } # => days_to_timestamp_s() # Convert certificate date to timestamp seconds since epoch # Used to verify iso_8601 calculated seconds since epoch cert_date_to_timestamp_s() { verbose "DEPRECATED: cert_date_to_timestamp_s" # check input [ "$#" = 2 ] || die "\ cert_date_to_timestamp_s: input error" #die "* NOT ALLOWED: cert_date_to_timestamp_s()" in_date="$1" # OS dependencies # Linux and Windows # date.exe does not allow +%s as input # MacPorts GNU date if timestamp_s="$( date -d "$in_date" +%s \ 2>/dev/null )" then : # ok # Darwin, BSD elif timestamp_s="$( date -j -f '%b %d %T %Y %Z' \ "$in_date" +%s 2>/dev/null )" then : # ok # busybox elif timestamp_s="$( busybox date -D "%b %e %H:%M:%S %Y" \ -d "$in_date" +%s 2>/dev/null )" then : # ok # Something else else die "\ cert_date_to_timestamp_s: 'date' failed for in_date=$in_date" fi # Return timestamp_s force_set_var "$2" "$timestamp_s" || die "\ cert_date_to_timestamp_s: force_set_var - $2 - $timestamp_s" unset -v in_date timestamp_s } # => cert_date_to_timestamp_s() # Build a Windows date.exe compatible input field # iso_8601 date db_date_to_iso_8601_date() { verbose "iso_8601: db_date_to_iso_8601_date" # check input [ "$#" = 2 ] || die "\ db_date_to_iso_8601_date - input error" # Expected format: '230612235959Z' in_date="$1" verbose "db_date_to_iso_8601_date: in_date=$in_date" # Consume $in_date string # yyyy is expected to be only 'yy' yyyy="${in_date%???????????}" in_date="${in_date#"$yyyy"}" # When yyyy is only two digits prepend century if [ "${#yyyy}" = 2 ]; then yyyy="${yyyy#0}" if [ "$yyyy" -lt 70 ]; then if [ "${#yyyy}" = 2 ]; then yyyy="20${yyyy}" else yyyy="200${yyyy}" fi else if [ "${#yyyy}" = 2 ]; then yyyy="19${yyyy}" else yyyy="190${yyyy}" fi fi fi verbose "db_date_to_iso_8601_date: yyyy=$yyyy" mm="${in_date%?????????}" in_date="${in_date#"$mm"}" dd="${in_date%???????}" in_date="${in_date#"$dd"}" HH="${in_date%?????}" in_date="${in_date#"$HH"}" MM="${in_date%???}" in_date="${in_date#"$MM"}" SS="${in_date%?}" in_date="${in_date#"$SS"}" TZ="$in_date" # Assign iso_8601 date out_date="${yyyy}-${mm}-${dd} ${HH}:${MM}:${SS}${TZ}" verbose "db_date_to_iso_8601_date: out_date=$out_date" # Return out_date force_set_var "$2" "$out_date" || die "\ db_date_to_iso_8601_date: force_set_var - $2 - $out_date" unset -v in_date out_date yyyy mm dd HH MM SS TZ } # => db_date_to_iso_8601_date() # Convert default SSL date to iso_8601 date # This may not be feasible, due to different languages # Alow the caller to assess those errors (eg. Fall-back) cert_date_to_iso_8601_date() { verbose "iso_8601-WIP: cert_date_to_iso_8601_date" die "BLOCKED: cert_date_to_iso_8601_date" # check input [ "$#" = 2 ] || die "\ cert_date_to_iso_8601_date: input error" # Expected format: 'Mar 21 18:25:01 2023 GMT' in_date="$1" # Consume in_date string mmm="${in_date%% *}" in_date="${in_date#"$mmm" }" dd="${in_date%% *}" in_date="${in_date#"$dd" }" HH="${in_date%%:*}" in_date="${in_date#"$HH":}" MM="${in_date%%:*}" in_date="${in_date#"$MM":}" SS="${in_date%% *}" in_date="${in_date#"$SS" }" yyyy="${in_date%% *}" in_date="${in_date#"$yyyy" }" TZ="$in_date" # Assign month number by abbreviation case "$mmm" in Jan) mm="01" ;; Feb) mm="02" ;; Mar) mm="03" ;; Apr) mm="04" ;; May) mm="05" ;; Jun) mm="06" ;; Jul) mm="07" ;; Aug) mm="08" ;; Sep) mm="09" ;; Oct) mm="10" ;; Nov) mm="11" ;; Dec) mm="12" ;; *) information "Only english dates are currently supported." warn "cert_date_to_iso_8601_date - Unknown month: '$mmm'" # The caller is REQUIRED to assess this error return 1 esac # Assign signle letter timezone from abbreviation case "$TZ" in GMT) TZ=Z ;; *) information "Only english dates are currently supported." warn "cert_date_to_iso_8601_date - Unknown timezone: '$TZ'" # The caller is REQUIRED to assess this error return 1 esac # Assign iso_8601 date out_date="${yyyy}-${mm}-${dd} ${HH}:${MM}:${SS}${TZ}" # Return iso_8601 date force_set_var "$2" "$out_date" || die "\ cert_date_to_iso_8601: force_set_var - $2 - $out_date" unset -v in_date out_date yyyy mmm mm dd HH MM SS TZ } # => cert_date_to_iso_8601() # SC2295: Expansion inside ${..} need to be quoted separately, # otherwise they match as patterns. (what-ever that means ;-) # Unfortunately, Windows sh.exe has an weird bug. # Try in sh.exe: t=' '; s="a${t}b${t}c"; echo "${s%%"${t}"*}" # Read db # shellcheck disable=SC2295 read_db() { TCT=' ' # tab character db_in="$EASYRSA_PKI/index.txt" pki_r_issued="$EASYRSA_PKI/renewed/issued" pki_r_by_sno="$EASYRSA_PKI/renewed/certs_by_serial" unset -v target_found while read -r db_status db_notAfter db_record; do verbose "***** Read next record *****" # Recreate temp session remove_secure_session || \ die "read_db - remove_secure_session" secure_session || \ die "read_db - secure_session" # Interpret the db/certificate record unset -v db_serial db_cn db_revoke_date db_reason case "$db_status" in V|E) # Valid db_serial="${db_record%%${TCT}*}" db_record="${db_record#*${TCT}}" db_cn="${db_record#*/CN=}"; db_cn="${db_cn%%/*}" cert_issued="$EASYRSA_PKI/issued/$db_cn.crt" cert_r_issued="$pki_r_issued/$db_cn.crt" cert_r_by_sno="$pki_r_by_sno/$db_serial.crt" ;; R) # Revoked db_revoke_date="${db_record%%${TCT}*}" db_reason="${db_revoke_date#*,}" if [ "$db_reason" = "$db_revoke_date" ]; then db_reason="None given" else db_revoke_date="${db_revoke_date%,*}" fi db_record="${db_record#*${TCT}}" db_serial="${db_record%%${TCT}*}" db_record="${db_record#*${TCT}}" db_cn="${db_record#*/CN=}"; db_cn="${db_cn%%/*}" ;; *) die "Unexpected status: $db_status" esac # Output selected status report for this record case "$report" in expire) # Certs which expire before EASYRSA_PRE_EXPIRY_WINDOW days case "$db_status" in V|E) case "$target" in '') expire_status ;; *) if [ "$target" = "$db_cn" ]; then expire_status fi esac ;; *) : # Ignore ok esac ;; revoke) # Certs which have been revoked case "$db_status" in R) case "$target" in '') revoke_status ;; *) if [ "$target" = "$db_cn" ]; then revoke_status fi esac ;; *) : # Ignore ok esac ;; renew) # Certs which have been renewed but not revoked case "$db_status" in V|E) case "$target" in '') renew_status ;; *) if [ "$target" = "$db_cn" ]; then renew_status fi esac ;; *) : # Ignore ok esac ;; *) die "Unrecognised report: $report" esac # Is db record for target found if [ "$target" = "$db_cn" ]; then target_found=1 fi done < "$db_in" # Check for target found/valid commonName, if given if [ "$target" ]; then [ "$target_found" ] || \ warn "Certificate for $target was not found" fi } # => read_db() # Expire status expire_status() { unset -v expire_status_cert_exists pre_expire_window_s="$(( EASYRSA_PRE_EXPIRY_WINDOW * 60*60*24 ))" # The certificate for CN should exist but may not unset -v expire_status_cert_exists if [ -e "$cert_issued" ]; then verbose "expire_status: cert exists" expire_status_cert_exists=1 # get the serial number of the certificate ssl_cert_serial "$cert_issued" cert_serial # db serial must match certificate serial, otherwise # this is a renewed cert which has been replaced by # an issued cert if [ "$db_serial" != "$cert_serial" ]; then information "\ expire_status: SERIAL MISMATCH db_serial: $db_serial cert_serial: $cert_serial commonName: $db_cn cert_issued: $cert_issued${NL}" #return 0 fi # Get cert end date in iso_8601 format from SSL # or fall-back to old format # Redirect SSL error to /dev/null here not in function cert_not_after_date= if iso_8601_cert_enddate \ "$cert_issued" cert_not_after_date 2>/dev/null then : # ok else verbose "\ expire_status: ACCEPTED ERROR-1: \ from iso_8601_cert_enddate" verbose "\ expire_status: CONSUMED ERROR: \ FALL-BACK to default SSL date format" ssl_cert_not_after_date \ "$cert_issued" cert_not_after_date verbose "\ expire_status: FALL-BACK completed" fi else verbose "expire_status: cert does NOT exist" # Translate db date to 8601_date cert_not_after_date= db_date_to_iso_8601_date \ "$db_notAfter" cert_not_after_date # Translate 8601_date to time-stamp-seconds iso_8601_timestamp_to_seconds \ "$cert_not_after_date" cert_expire_date_s # Cert does not exist fi # Only verify if there is a certificate if [ "$expire_status_cert_exists" ]; then # Check cert expiry against window # openssl direct call because error is expected if OPENSSL_CONF=/dev/null \ "$EASYRSA_OPENSSL" x509 -in "$cert_issued" \ -noout -checkend "$pre_expire_window_s" \ 1>/dev/null then expire_msg="will NOT expire" will_not_expire=1 unset -v will_expire else expire_msg="will expire" will_expire=1 unset -v will_not_expire fi verbose "expire_status: SSL checkend: $expire_msg" # Get timestamp seconds for certificate expiry date # Redirection for errout is not necessary here cert_expire_date_s= if iso_8601_timestamp_to_seconds \ "$cert_not_after_date" cert_expire_date_s then : # ok # Verify dates via 'date +%s' format verbose "\ expire_status: cert_date_to_timestamp_s: for comparison" old_cert_expire_date_s= cert_date_to_timestamp_s \ "$cert_not_after_date" old_cert_expire_date_s # Prove this works if [ "$cert_expire_date_s" = "$old_cert_expire_date_s" ] then verbose "\ expire_status: ABSOLUTE seconds MATCH: cert_expire_date_s= $cert_expire_date_s old_cert_expire_date_s= $old_cert_expire_date_s" else verbose "\ expire_status: ABSOLUTE seconds do not MATCH: cert_expire_date_s= $cert_expire_date_s old_cert_expire_date_s= $old_cert_expire_date_s difference= \ $(( cert_expire_date_s - old_cert_expire_date_s ))" # If there is an error then use --days-margin=10 [ "$EASYRSA_iso_8601_MARGIN" ] || \ die "\ expire_status - ABSOLUTE seconds mismatch: Use --allow-margin=N" # Allows days for margin of error in seconds margin_s="$(( EASYRSA_iso_8601_MARGIN * (60 * 60 * 24) + 1 ))" margin_plus_s="$(( old_cert_expire_date_s + margin_s ))" margin_minus_s="$(( old_cert_expire_date_s - margin_s ))" if [ "$cert_expire_date_s" -lt "$margin_plus_s" ] && [ "$cert_expire_date_s" -gt "$margin_minus_s" ] then : # ok verbose "\ expire_status: MARGIN seconds ACCEPTED: cert_expire_date_s= $cert_expire_date_s old_cert_expire_date_s= $old_cert_expire_date_s difference= \ $(( cert_expire_date_s - old_cert_expire_date_s )) margin_plus_s= $margin_plus_s margin_minus_s= $margin_minus_s" else verbose "\ expire_status: MARGIN seconds REJECTED: cert_expire_date_s= $cert_expire_date_s old_cert_expire_date_s= $old_cert_expire_date_s margin_plus_s= $margin_plus_s margin_minus_s= $margin_minus_s" die "\ expire_status: Verify cert expire date EXCESS mismatch!" fi fi verbose "\ expire_status: cert_date_to_timestamp_s: comparison complete" else verbose "\ expire_status: ACCEPTED ERROR-2: \ iso_8601_timestamp_to_seconds" verbose "\ expire_status: CONSUMED ERROR: \ FALL-BACK to default SSL date format" cert_date_to_timestamp_s \ "$cert_not_after_date" cert_expire_date_s verbose "\ expire_status: FALL-BACK completed" fi fi # Convert number of days to a timestamp in seconds cutoff_date_s= days_to_timestamp_s \ "$EASYRSA_PRE_EXPIRY_WINDOW" cutoff_date_s # Get the current date/time as a timestamp in seconds now_date_s= days_to_timestamp_s \ 0 now_date_s # Compare and print output if [ "$cert_expire_date_s" -lt "$cutoff_date_s" ]; then # Cert expires in less than grace period if [ "$will_not_expire" ]; then die "\ EasyRSA: will expire - SSL: will NOT expire" fi if [ "$cert_expire_date_s" -gt "$now_date_s" ]; then verbose "expire_status: Valid -> expiring" printf '%s%s\n' \ "$db_status | Serial: $db_serial | " \ "Expires: $cert_not_after_date | CN: $db_cn" else verbose "expire_status: Expired" printf '%s%s\n' \ "$db_status | Serial: $db_serial | " \ "Expired: $cert_not_after_date | CN: $db_cn" fi else if [ "$will_expire" ]; then die "\ EasyRSA: will NOT expire - SSL: will expire" fi verbose "expire_status: Valid -> NOT expiring" fi } # => expire_status() # Revoke status revoke_status() { # Translate db date to usable date cert_revoke_date= db_date_to_iso_8601_date "$db_revoke_date" cert_revoke_date printf '%s%s%s\n' \ "$db_status | Serial: $db_serial | " \ "Revoked: $cert_revoke_date | " \ "Reason: $db_reason | CN: $db_cn" } # => revoke_status() # Renewed status # renewed certs only remain in the renewed folder until revoked # Only ONE renewed cert with unique CN can exist in renewed folder renew_status() { # Does a Renewed cert exist ? # files in issued are file name, or in serial are SerialNumber unset -v \ cert_file_in cert_is_issued cert_is_serial renew_is_old # Find renewed/issued/CN if [ -e "$cert_r_issued" ]; then cert_file_in="$cert_r_issued" cert_is_issued=1 fi # Find renewed/cert_by_serial/SN if [ -e "$cert_r_by_sno" ]; then cert_file_in="$cert_r_by_sno" cert_is_serial=1 renew_is_old=1 fi # Both should not exist if [ "$cert_is_issued" ] && [ "$cert_is_serial" ]; then die "Too many certs" fi # If a renewed cert exists if [ "$cert_file_in" ]; then # get the serial number of the certificate ssl_cert_serial "$cert_file_in" cert_serial # db serial must match certificate serial, otherwise # this is an issued cert that replaces a renewed cert if [ "$db_serial" != "$cert_serial" ]; then information "\ serial mismatch: db_serial: $db_serial cert_serial: $cert_serial cert_file_in: $cert_file_in" return 0 fi # Use cert date # Assigns cert_not_after_date ssl_cert_not_after_date \ "$cert_file_in" cert_not_after_date # Highlight renewed/cert_by_serial if [ "$renew_is_old" ]; then printf '%s%s\n' \ "*** $db_status | Serial: $db_serial | " \ "Expires: $cert_not_after_date | CN: $db_cn" else printf '%s%s\n' \ "$db_status | Serial: $db_serial | " \ "Expires: $cert_not_after_date | CN: $db_cn" fi else # Cert is valid but not renewed : # ok - ignore fi } # => renew_status() # cert status reports status() { [ "$#" -gt 0 ] || die "status - input error" report="$1" target="$2" # test fix: https://github.com/OpenVPN/easy-rsa/issues/819 export LC_TIME=C.UTF-8 # If no target file then add Notice if [ -z "$target" ]; then # Select correct Notice case "$report" in expire) notice "\ * Showing certificates which expire in less than \ $EASYRSA_PRE_EXPIRY_WINDOW days (--days):" ;; revoke) notice "\ * Showing certificates which are revoked:" ;; renew) notice "\ * Showing certificates which have been renewed but NOT revoked: *** Marks those which require 'rewind-renew' \ before they can be revoked." ;; *) warn "Unrecognised report: $report" esac fi # Create report read_db } # => status() # set_var is not known by shellcheck, therefore: # Fake declare known variables for shellcheck # Use these options without this function: # -o all -e 2250,2244,2248 easyrsa satisfy_shellcheck() { die "Security feature enabled!" # Add more as/if required # Enable the heredoc for a peek #cat << SC2154 EASYRSA= EASYRSA_OPENSSL= EASYRSA_PKI= EASYRSA_DN= EASYRSA_REQ_COUNTRY= EASYRSA_REQ_PROVINCE= EASYRSA_REQ_CITY= EASYRSA_REQ_ORG= EASYRSA_REQ_EMAIL= EASYRSA_REQ_OU= EASYRSA_ALGO= EASYRSA_KEY_SIZE= EASYRSA_CURVE= EASYRSA_CA_EXPIRE= EASYRSA_CERT_EXPIRE= EASYRSA_PRE_EXPIRY_WINDOW= EASYRSA_CRL_DAYS= EASYRSA_NS_SUPPORT= EASYRSA_NS_COMMENT= EASYRSA_TEMP_DIR= EASYRSA_REQ_CN= EASYRSA_DIGEST= EASYRSA_SSL_CONF= EASYRSA_SAFE_CONF= OPENSSL_CONF= #EASYRSA_KDC_REALM= EASYRSA_RAND_SN= KSH_VERSION= #SC2154 } # => satisfy_shellcheck() # Identify host OS detect_host() { unset -v \ easyrsa_ver_test easyrsa_host_os easyrsa_host_test \ easyrsa_win_git_bash # Detect Windows [ "${OS}" ] && easyrsa_host_test="${OS}" # shellcheck disable=SC2016 # expansion inside '' blah easyrsa_ksh=\ '@(#)MIRBSD KSH R39-w32-beta14 $Date: 2013/06/28 21:28:57 $' [ "${KSH_VERSION}" = "${easyrsa_ksh}" ] && \ easyrsa_host_test="${easyrsa_ksh}" unset -v easyrsa_ksh # If not Windows then nix if [ "${easyrsa_host_test}" ]; then easyrsa_host_os=win easyrsa_uname="${easyrsa_host_test}" easyrsa_shell="$SHELL" # Detect Windows git/bash if [ "${EXEPATH}" ]; then easyrsa_shell="$SHELL (Git)" easyrsa_win_git_bash="${EXEPATH}" # If found then set openssl NOW! #[ -e /usr/bin/openssl ] && \ # set_var EASYRSA_OPENSSL /usr/bin/openssl fi else easyrsa_host_os=nix easyrsa_uname="$(uname 2>/dev/null)" easyrsa_shell="${SHELL:-undefined}" fi easyrsa_ver_test="${EASYRSA_version%%~*}" if [ "$easyrsa_ver_test" ]; then host_out="Host: $EASYRSA_version" else host_out="Host: dev" fi host_out="\ $host_out | $easyrsa_host_os | $easyrsa_uname | $easyrsa_shell" host_out="\ ${host_out}${easyrsa_win_git_bash+ | "$easyrsa_win_git_bash"}" unset -v easyrsa_ver_test easyrsa_host_test } # => detect_host() # Extra diagnostics show_host() { [ "$EASYRSA_SILENT" ] && return print_version print "$host_out" [ "$EASYRSA_DEBUG" ] || return 0 case "$easyrsa_host_os" in win) set ;; nix) env ;; *) print "Unknown host OS: $easyrsa_host_os" esac } # => show_host() # Verify the selected algorithm parameters verify_algo_params() { case "$EASYRSA_ALGO" in rsa) # Set RSA key size EASYRSA_ALGO_PARAMS="$EASYRSA_KEY_SIZE" ;; ec) # Verify Elliptic curve EASYRSA_ALGO_PARAMS="" easyrsa_mktemp EASYRSA_ALGO_PARAMS || \ die "\ verify_algo_params - easyrsa_mktemp EASYRSA_ALGO_PARAMS" # Create the required ecparams file # call openssl directly because error is expected OPENSSL_CONF=/dev/null \ "$EASYRSA_OPENSSL" ecparam \ -name "$EASYRSA_CURVE" \ -out "$EASYRSA_ALGO_PARAMS" \ 1>/dev/null || die "\ Failed to generate ecparam file (permissions?) at: * $EASYRSA_ALGO_PARAMS" ;; ed) # Verify Edwards curve # call openssl directly because error is expected OPENSSL_CONF=/dev/null \ "$EASYRSA_OPENSSL" genpkey \ -algorithm "$EASYRSA_CURVE" \ 1>/dev/null || die "\ Edwards Curve $EASYRSA_CURVE not found." ;; *) user_error "\ Unknown algorithm '$EASYRSA_ALGO': Must be 'rsa', 'ec' or 'ed'" esac verbose "\ verify_algo_params: Params verified for algo '$EASYRSA_ALGO'" } # => verify_algo_params() # Check for conflicting input options mutual_exclusions() { # --nopass cannot be used with --passout if [ "$EASYRSA_PASSOUT" ]; then # --passout MUST take priority over --nopass [ "$EASYRSA_NO_PASS" ] && warn "\ Option --passout cannot be used with --nopass|nopass." unset -v EASYRSA_NO_PASS prohibit_no_pass=1 fi # --silent-ssl requires --batch if [ "$EASYRSA_SILENT_SSL" ]; then [ "$EASYRSA_BATCH" ] || warn "\ Option --silent-ssl requires batch mode --batch." fi # --startdate requires --enddate # otherwise, --days counts from now if [ "$EASYRSA_START_DATE" ]; then [ "$EASYRSA_END_DATE" ] || user_error "\ Use of --startdate requires use of --enddate." fi # --enddate may over-rule EASYRSA_CERT_EXPIRE if [ "$EASYRSA_END_DATE" ]; then case "$cmd" in sign-req|build-*-full|renew|rebuild) # User specified alias_days IS over-ruled if [ "$alias_days" ]; then warn "\ Option --days is over-ruled by option --enddate." fi unset -v EASYRSA_CERT_EXPIRE alias_days ;; *) warn "\ EasyRSA '$cmd' does not support --startdate or --enddate" unset -v EASYRSA_START_DATE EASYRSA_END_DATE esac fi # Insecure Windows directory if [ "$easyrsa_host_os" = win ]; then if echo "$PWD" | grep -q '/Prog.*/OpenVPN/easy-rsa' then verbose "\ Using Windows-System-Folders for your PKI is NOT SECURE! Your Easy-RSA PKI CA Private Key is WORLD readable. To correct this problem, it is recommended that you either: * Copy Easy-RSA to your User folders and run it from there, OR * Define your PKI to be in your User folders. EG: 'easyrsa --pki-dir=\"C:/Users//easy-rsa/pki\"\ '" fi fi verbose "mutual_exclusions: COMPLETED" } # => mutual_exclusions() # Select vars in order preference: # Here sourcing of 'vars' if present occurs. # If not present, defaults are used to support # running without a sourced config format. select_vars() { # No vars file will be used if [ "$EASYRSA_NO_VARS" ]; then verbose "select_vars: EASYRSA_NO_VARS" unset -v EASYRSA_VARS_FILE # skip the rest of this function return # User specified vars file will be used ONLY elif [ "$EASYRSA_VARS_FILE" ]; then # Takes priority, nothing to do verbose "select_vars: EASYRSA_VARS_FILE" # This is where auto-load goes bananas else # User specified PKI; if vars exists, use it ONLY if [ "$EASYRSA_PKI" ]; then if [ -e "$EASYRSA_PKI/vars" ]; then verbose "select_vars: source EASYRSA_PKI/vars" set_var EASYRSA_VARS_FILE "$EASYRSA_PKI/vars" fi fi # User specified EASYRSA; if vars exists, use it ONLY if [ "$EASYRSA" ]; then if [ -e "$EASYRSA/vars" ]; then verbose "select_vars: EASYRSA/vars" set_var EASYRSA_VARS_FILE "$EASYRSA/vars" fi fi # Default PKI; if vars exists, use it ONLY if [ -e "$PWD/pki/vars" ] && \ [ -z "$EASYRSA_PKI" ] && \ [ -z "$EASYRSA" ] then # Prevent vars from changing expected PKI. # A vars in the PKI MUST always imply EASYRSA_PKI # This is NOT backward compatible # Use expected value comparison for v3.1.7 if [ -z "$EASYRSA_VARS_FILE" ]; then expected_EASYRSA="$PWD" expected_EASYRSA_PKI="$PWD/pki" fi # Use this for v3.2.0 # If the pki/vars sets a different PKI then # there will be no PKI in the default /pki #set_var EASYRSA "$PWD" #set_var EASYRSA_PKI "$EASYRSA/pki" verbose "select_vars: PWD/pki/vars" set_var EASYRSA_VARS_FILE "$PWD/pki/vars" fi # Default working dir; if vars exists, use it ONLY if [ -e "$PWD/vars" ]; then verbose "select_vars: PWD/vars" set_var EASYRSA_VARS_FILE "$PWD/vars" fi fi # User info if [ -z "$EASYRSA_VARS_FILE" ]; then [ "$require_pki" ] && information "\ No Easy-RSA 'vars' configuration file exists!" EASYRSA_NO_VARS=1 fi } # => select_vars() # Source a vars file source_vars() { # Never use vars file if [ "$EASYRSA_NO_VARS" ]; then verbose "source_vars: EASYRSA_NO_VARS" return fi # File to be sourced target_file="$1" # 'vars' MUST not be a directory [ -d "$target_file" ] && user_error "\ Missing vars file: * $target_file" # 'vars' now MUST exist [ -e "$target_file" ] || user_error "\ Missing vars file: * $target_file" # Installation information [ "$require_pki" ] && information "\ Using Easy-RSA 'vars' configuration: * $target_file" # Sanitize vars if grep -q \ -e 'EASYRSA_PASSIN' -e 'EASYRSA_PASSOUT' \ -e '[^(]`[^)]' \ "$target_file" then user_error "\ One or more of these problems has been found in your 'vars' file: * $target_file * Use of 'EASYRSA_PASSIN' or 'EASYRSA_PASSOUT': Storing password information in the 'vars' file is not permitted. * Use of unsupported characters: These characters are not supported: \` backtick Please, correct these errors and try again." fi # Sanitize vars if grep -q \ -e '[[:blank:]]export[[:blank:]]*' \ -e '[[:blank:]]unset[[:blank:]]*' \ "$target_file" then user_error "\ One or more of these problems has been found in your 'vars' file: * $target_file * Use of 'export': Remove 'export' or replace it with 'set_var'. * Use of 'unset': Remove 'unset' ('force_set_var' may also work)." fi # Enable sourcing 'vars' # shellcheck disable=SC2034 # appears unused EASYRSA_CALLER=1 easyrsa_path="$PATH" # shellcheck disable=SC2123 # PATH is the shell .. PATH=./ # Test sourcing 'vars' in a subshell # shellcheck disable=1090 # can't follow .. vars if ( . "$target_file" ); then # Source 'vars' now # shellcheck disable=1090 # can't follow .. vars . "$target_file" || \ die "Failed to source the '$target_file' file." else PATH="$easyrsa_path" die "Failed to dry-run the '$target_file' file." fi PATH="$easyrsa_path" verbose "source_vars: sourced OK '$target_file'" unset -v EASYRSA_CALLER easyrsa_path target_file } # => source_vars() # Set defaults default_vars() { # Set defaults, preferring existing env-vars if present set_var EASYRSA "$PWD" set_var EASYRSA_OPENSSL openssl set_var EASYRSA_PKI "$EASYRSA/pki" set_var EASYRSA_DN cn_only set_var EASYRSA_REQ_COUNTRY "US" set_var EASYRSA_REQ_PROVINCE "California" set_var EASYRSA_REQ_CITY "San Francisco" set_var EASYRSA_REQ_ORG "Copyleft Certificate Co" set_var EASYRSA_REQ_EMAIL me@example.net set_var EASYRSA_REQ_OU "My Organizational Unit" set_var EASYRSA_REQ_SERIAL "" set_var EASYRSA_ALGO rsa set_var EASYRSA_KEY_SIZE 2048 case "$EASYRSA_ALGO" in rsa) : # ok # default EASYRSA_KEY_SIZE must always be set # it must NOT be set selectively because it is # present in the SSL config file ;; ec) set_var EASYRSA_CURVE secp384r1 ;; ed) set_var EASYRSA_CURVE ed25519 ;; *) user_error "\ Algorithm '$EASYRSA_ALGO' is invalid: Must be 'rsa', 'ec' or 'ed'" esac set_var EASYRSA_CA_EXPIRE 3650 set_var EASYRSA_CERT_EXPIRE 825 set_var \ EASYRSA_PRE_EXPIRY_WINDOW 90 set_var EASYRSA_CRL_DAYS 180 set_var EASYRSA_NS_SUPPORT no set_var EASYRSA_NS_COMMENT \ "Easy-RSA (3.1.7) Generated Certificate" set_var EASYRSA_TEMP_DIR "$EASYRSA_PKI" set_var EASYRSA_REQ_CN ChangeMe set_var EASYRSA_DIGEST sha256 set_var EASYRSA_SSL_CONF \ "$EASYRSA_PKI/openssl-easyrsa.cnf" set_var EASYRSA_SAFE_CONF \ "$EASYRSA_PKI/safessl-easyrsa.cnf" set_var EASYRSA_KDC_REALM "CHANGEME.EXAMPLE.COM" set_var EASYRSA_MAX_TEMP 4 } # => default_vars() # Validate expected values for EASYRSA and EASYRSA_PKI validate_default_vars() { unset -v unexpected_error # Keep checks separate # EASYRSA if [ "$expected_EASYRSA" ]; then [ "$expected_EASYRSA" = "$EASYRSA" ] || \ unexpected_error="\ EASYRSA: $EASYRSA Expected: $expected_EASYRSA" fi # EASYRSA_PKI if [ "$expected_EASYRSA_PKI" ]; then if [ "$expected_EASYRSA_PKI" = "$EASYRSA_PKI" ]; then : # ok else if [ "$unexpected_error" ]; then # Add a new-line Extra separator, for clarity unexpected_error="${unexpected_error}${NL}${NL}" fi unexpected_error="${unexpected_error}\ EASYRSA_PKI: $EASYRSA_PKI Expected: $expected_EASYRSA_PKI" fi fi # Return no error [ -z "$unexpected_error" ] && return # This is an almost unacceptable error invalid_vars=1 [ "$ignore_vars" ] || user_error "\ The values in the vars file have unexpectedly changed the values for EASYRSA and/or EASYRSA_PKI. The default pki/vars file is forbidden to change these values. vars-file: $EASYRSA_VARS_FILE ${unexpected_error}" } # => validate_default_vars() # Verify working environment verify_working_env() { # Verify SSL Lib - One time ONLY verify_ssl_lib # Find x509-types but do not fail # Not fatal here, used by 'help' install_data_to_pki x509-types-only # For commands which 'require a PKI' and PKI exists if [ "$require_pki" ]; then # Verify PKI is initialised verify_pki_init # Temp dir MUST exist if [ -d "$EASYRSA_TEMP_DIR" ]; then # Temp dir session secure_session || die "\ verify_working_env - secure-session failed" # Install data-files into ALL PKIs # This will find x509-types # and export EASYRSA_EXT_DIR or die. # Other errors only require warning. install_data_to_pki vars-setup || warn "\ verify_working_env - install_data_to_pki vars-setup failed" # Verify selected algorithm and parameters verify_algo_params # Check $working_safe_ssl_conf, to build # a fully configured safe ssl conf, on the # next invocation of easyrsa_openssl() if [ "$working_safe_ssl_conf" ]; then die "working_safe_ssl_conf must not be set!" fi # Verify CA is initialised if [ "$require_ca" ]; then verify_ca_init fi # Last setup msg information " Using SSL: * $EASYRSA_OPENSSL $ssl_version" else # The directory does not exist user_error "\ Temporary directory does not exist: * $EASYRSA_TEMP_DIR" fi fi verbose "verify_working_env: COMPLETED" } # => verify_working_env() # variable assignment by indirection. # Sets '$1' as the value contained in '$2' # and exports (may be blank) set_var() { [ -z "$*" ] && return [ -z "$3" ] || \ user_error "set_var - excess input '$*'" case "$1" in *=*) user_error "set_var - var '$1'" esac eval "export \"$1\"=\"\${$1-$2}\"" && return die "set_var - eval '$*'" } # => set_var() # sanatize and set var # nix.sh/win.sh/busybox.sh never return error from unset # when an invalid variable name 'a=b' is used with a value # to set, eg. 'c'; This causes EasyRSA to execute: # eval "export a=b=c". 'set_var EASYRSA_PKI=pki' results in # $EASYRSA_PKI being set to 'pki=pki-', without error! # Guard against this possible user error with 'case'. force_set_var() { [ -z "$3" ] || \ user_error "force_set_var - excess input '$*'" case "$1" in *=*) user_error "force_set_var - var '$1'" esac # Guard unset with '|| die', just in case unset -v "$1" || die "force_set_var - unset '$1'" set_var "$1" "$2" && return die "force_set_var - set_var '$*'" } # => force_set_var() ############################################################################ # # Create X509-type files create_x509_type() { case "$1" in COMMON) cat <<- "X509_TYPE_COMMON" X509_TYPE_COMMON ;; serverClient) create_x509_type_easyrsa cat <<- "X509_TYPE_SERV_CLI" extendedKeyUsage = serverAuth,clientAuth X509_TYPE_SERV_CLI ;; server) create_x509_type_easyrsa cat <<- "X509_TYPE_SERV" extendedKeyUsage = serverAuth X509_TYPE_SERV ;; client) create_x509_type_easyrsa cat <<- "X509_TYPE_CLI" extendedKeyUsage = clientAuth X509_TYPE_CLI ;; ca) cat <<- "X509_TYPE_CA" basicConstraints = CA:TRUE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always keyUsage = cRLSign, keyCertSign X509_TYPE_CA ;; *) # Unknown type: User MUST supply the X509 file die "create_x509_type - Unknown X509 type: '$1'" esac } # => create_x509_type() # Create x509-type/easyrsa # This could be COMMON but not is not suitable for a CA create_x509_type_easyrsa() { cat <<- "X509_TYPE_EASYRSA" basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = digitalSignature,keyEncipherment X509_TYPE_EASYRSA } # => create_x509_type_easyrsa() # Create vars.example - Minimum settings only create_vars_example() { cat << "VARS_EXAMPLE" # Easy-RSA 3 parameter settings # NOTE: If you installed Easy-RSA from your package manager, do not edit # this file in place -- instead, you should copy the entire easy-rsa directory # to another location so future upgrades do not wipe out your changes. # HOW TO USE THIS FILE # # vars.example contains built-in examples to Easy-RSA settings. You MUST name # this file "vars" if you want it to be used as a configuration file. If you # do not, it WILL NOT be automatically read when you call easyrsa commands. # # It is not necessary to use this config file unless you wish to change # operational defaults. These defaults should be fine for many uses without # the need to copy and edit the "vars" file. # # All of the editable settings are shown commented and start with the command # "set_var" -- this means any set_var command that is uncommented has been # modified by the user. If you are happy with a default, there is no need to # define the value to its default. # NOTES FOR WINDOWS USERS # # Paths for Windows *MUST* use forward slashes, or optionally double-escaped # backslashes (single forward slashes are recommended.) This means your path # to the openssl binary might look like this: # "C:/Program Files/OpenSSL-Win32/bin/openssl.exe" # A little housekeeping: DO NOT EDIT THIS SECTION # # Easy-RSA 3.x does not source into the environment directly. # Complain if a user tries to do this: if [ -z "$EASYRSA_CALLER" ]; then echo "You appear to be sourcing an Easy-RSA *vars* file. This is" >&2 echo "no longer necessary and is disallowed. See the section called" >&2 echo "*How to use this file* near the top comments for more details." >&2 return 1 fi # DO YOUR EDITS BELOW THIS POINT # If your OpenSSL command is not in the system PATH, you will need to define # the path here. Normally this means a full path to the executable, otherwise # you could have left it undefined here and the shown default would be used. # # Windows users, remember to use paths with forward-slashes (or escaped # back-slashes.) Windows users should declare the full path to the openssl # binary here if it is not in their system PATH. # #set_var EASYRSA_OPENSSL "openssl" # # This sample is in Windows syntax -- edit it for your path if not using PATH: #set_var EASYRSA_OPENSSL "C:/Program Files/OpenSSL-Win32/bin/openssl.exe" # Define X509 DN mode. # # This is used to adjust which elements are included in the Subject field # as the DN ("Distinguished Name"). Note that in 'cn_only' mode the # Organizational fields, listed further below, are not used. # # Choices are: # cn_only - Use just a commonName value. # org - Use the "traditional" format: # Country/Province/City/Org/Org.Unit/email/commonName # #set_var EASYRSA_DN "cn_only" # Organizational fields (used with "org" mode and ignored in "cn_only" mode). # These are the default values for fields which will be placed in the # certificate. Do not leave any of these fields blank, although interactively # you may omit any specific field by typing the "." symbol (not valid for # email). # # NOTE: The following characters are not supported # in these "Organizational fields" by Easy-RSA: # back-tick (`) # #set_var EASYRSA_REQ_COUNTRY "US" #set_var EASYRSA_REQ_PROVINCE "California" #set_var EASYRSA_REQ_CITY "San Francisco" #set_var EASYRSA_REQ_ORG "Copyleft Certificate Co" #set_var EASYRSA_REQ_EMAIL "me@example.net" #set_var EASYRSA_REQ_OU "My Organizational Unit" # Preserve the Distinguished Name field order # of the certificate signing request # *Only* effective in --dn-mode=org # #set_var EASYRSA_PRESERVE_DN 1 # Set no password mode - This will create the entire PKI without passwords. # This can be better managed by choosing which entity private keys should be # encrypted with the following command line options: # Global option '--no-pass' or command option 'nopass'. # #set_var EASYRSA_NO_PASS 1 # Choose a size in bits for your keypairs. The recommended value is 2048. # Using 2048-bit keys is considered more than sufficient for many years into # the future. Larger keysizes will slow down TLS negotiation and make key/DH # param generation take much longer. Values up to 4096 should be accepted by # most software. Only used when the crypto alg is rsa, see below. # #set_var EASYRSA_KEY_SIZE 2048 # The default crypto mode is rsa; ec can enable elliptic curve support. # Note that not all software supports ECC, so use care when enabling it. # Choices for crypto alg are: (each in lower-case) # * rsa # * ec # * ed # #set_var EASYRSA_ALGO rsa # Define the named curve, used in ec & ed modes: # #set_var EASYRSA_CURVE secp384r1 # In how many days should the root CA key expire? # #set_var EASYRSA_CA_EXPIRE 3650 # In how many days should certificates expire? # #set_var EASYRSA_CERT_EXPIRE 825 # How many days until the next CRL publish date? Note that the CRL can still # be parsed after this timeframe passes. It is only used for an expected next # publication date. # #set_var EASYRSA_CRL_DAYS 180 # Random serial numbers by default. # Set to 'no' for the old incremental serial numbers. # #set_var EASYRSA_RAND_SN "yes" # Cut-off window for checking expiring certificates. # #set_var EASYRSA_PRE_EXPIRY_WINDOW 90 # Define directory for temporary subdirectories. # #set_var EASYRSA_TEMP_DIR "$EASYRSA_PKI" VARS_EXAMPLE } # => create_vars_example() # Create openssl-easyrsa.cnf create_openssl_easyrsa_cnf() { cat << "SSL_CONFIG" # For use with Easy-RSA 3.0+ and OpenSSL or LibreSSL #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = $ENV::EASYRSA_PKI # Where everything is kept certs = $dir # Where the issued certs are kept crl_dir = $dir # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/certs_by_serial # default place for new certs. certificate = $dir/ca.crt # The CA certificate serial = $dir/serial # The current serial number crl = $dir/crl.pem # The current CRL private_key = $dir/private/ca.key # The private key RANDFILE = $dir/.rand # private random number file x509_extensions = basic_exts # The extensions to add to the cert # A placeholder to handle the --copy-ext feature: #%COPY_EXTS% # Do NOT remove or change this line as --copy-ext support requires it # This allows a V2 CRL. Ancient browsers don't like it, but anything Easy-RSA # is designed for will. In return, we get the Issuer attached to CRLs. crl_extensions = crl_ext default_days = $ENV::EASYRSA_CERT_EXPIRE # how long to certify for default_crl_days = $ENV::EASYRSA_CRL_DAYS # how long before next CRL default_md = $ENV::EASYRSA_DIGEST # use public key default MD preserve = no # keep passed DN ordering # This allows to renew certificates which have not been revoked unique_subject = no # A few different ways of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_anything # For the 'anything' policy, which defines allowed DN fields [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional serialNumber = optional #################################################################### # Easy-RSA request handling # We key off $DN_MODE to determine how to format the DN [ req ] default_bits = $ENV::EASYRSA_KEY_SIZE default_keyfile = privkey.pem default_md = $ENV::EASYRSA_DIGEST distinguished_name = $ENV::EASYRSA_DN x509_extensions = easyrsa_ca # The extensions to add to the self signed cert # A placeholder to handle the $EXTRA_EXTS feature: #%EXTRA_EXTS% # Do NOT remove or change this line as $EXTRA_EXTS support requires it #################################################################### # Easy-RSA DN (Subject) handling # Easy-RSA DN for cn_only support: [ cn_only ] commonName = Common Name (eg: your user, host, or server name) commonName_max = 64 commonName_default = $ENV::EASYRSA_REQ_CN # Easy-RSA DN for org support: [ org ] countryName = Country Name (2 letter code) countryName_default = $ENV::EASYRSA_REQ_COUNTRY countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = $ENV::EASYRSA_REQ_PROVINCE localityName = Locality Name (eg, city) localityName_default = $ENV::EASYRSA_REQ_CITY 0.organizationName = Organization Name (eg, company) 0.organizationName_default = $ENV::EASYRSA_REQ_ORG organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = $ENV::EASYRSA_REQ_OU commonName = Common Name (eg: your user, host, or server name) commonName_max = 64 commonName_default = $ENV::EASYRSA_REQ_CN emailAddress = Email Address emailAddress_default = $ENV::EASYRSA_REQ_EMAIL emailAddress_max = 64 serialNumber = Serial-number (eg, device serial-number) serialNumber_default = $ENV::EASYRSA_REQ_SERIAL #################################################################### # Easy-RSA cert extension handling # This section is effectively unused as the main script sets extensions # dynamically. This core section is left to support the odd usecase where # a user calls openssl directly. [ basic_exts ] basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always # The Easy-RSA CA extensions [ easyrsa_ca ] # PKIX recommendations: subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always # This could be marked critical, but it's nice to support reading by any # broken clients who attempt to do so. basicConstraints = CA:true # Limit key usage to CA tasks. If you really want to use the generated pair as # a self-signed cert, comment this out. keyUsage = cRLSign, keyCertSign # nsCertType omitted by default. Let's try to let the deprecated stuff die. # nsCertType = sslCA # A placeholder to handle the $X509_TYPES and CA extra extensions $EXTRA_EXTS: #%CA_X509_TYPES_EXTRA_EXTS% # Do NOT remove or change this line as $X509_TYPES and EXTRA_EXTS demands it # CRL extensions. [ crl_ext ] # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always,issuer:always SSL_CONFIG } # => create_openssl_easyrsa_cnf() ############################################################################ # Upgrade v2 PKI to v3 PKI # You can report problems on the normal openvpn support channels: # -------------------------------------------------------------------------- # 1. The Openvpn Forum: https://forums.openvpn.net/viewforum.php?f=31 # 2. The #easyrsa IRC channel at libera.chat # 3. Info: https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade # -------------------------------------------------------------------------- # up23_fail_upgrade () { # Replace die() unset -v EASYRSA_BATCH notice " ============================================================================ The update has failed but NOTHING has been lost. ERROR: $1 ---------------------------------------------------------------------------- Further info: * https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade#ersa-up23-fails Easyrsa3 upgrade FAILED ============================================================================ " exit 9 } #=> up23_fail_upgrade () up23_verbose () { [ "$VERBOSE" ] || return 0 printf "%s\n" "$1" } #=> up23_verbose () up23_verify_new_pki () { # Fail now, before any changes are made up23_verbose "> Verify DEFAULT NEW PKI does not exist .." EASYRSA_NEW_PKI="$EASYRSA/pki" [ -d "$EASYRSA_NEW_PKI" ] \ && up23_fail_upgrade "DEFAULT NEW PKI exists: $EASYRSA_NEW_PKI" up23_verbose "> Verify VERY-SAFE-PKI does not exist .." EASYRSA_SAFE_PKI="$EASYRSA/VERY-SAFE-PKI" [ -d "$EASYRSA_SAFE_PKI" ] \ && up23_fail_upgrade "VERY-SAFE-PKI exists: $EASYRSA_SAFE_PKI" up23_verbose "> Verify openssl-easyrsa.cnf does exist .." EASYRSA_SSL_CNFFILE="$EASYRSA/openssl-easyrsa.cnf" [ -f "$EASYRSA_SSL_CNFFILE" ] \ || up23_fail_upgrade "cannot find $EASYRSA_SSL_CNFFILE" up23_verbose "> Verify vars.example does exist .." EASYRSA_VARSV3_EXMP="$EASYRSA/vars.example" [ -f "$EASYRSA_VARSV3_EXMP" ] \ || up23_fail_upgrade "cannot find $EASYRSA_VARSV3_EXMP" up23_verbose "> OK" up23_verbose " Initial dirs & files are in a workable state." } #=> up23_verify_new_pki () # shellcheck disable=SC2154 up23_verify_current_pki () { up23_verbose "> Verify CURRENT PKI vars .." # This can probably be improved EASYRSA_NO_REM="$(grep '^set ' "$EASYRSA_VER2_VARSFILE")" # This list may not be complete # Not required: DH_KEY_SIZE PKCS11_MODULE_PATH PKCS11_PIN for i in KEY_DIR KEY_SIZE KEY_COUNTRY KEY_PROVINCE \ KEY_CITY KEY_ORG KEY_EMAIL KEY_CN KEY_NAME KEY_OU do # Effectively, source the v2 vars file UNIQUE="set $i" KEY_grep="$(printf "%s\n" "$EASYRSA_NO_REM" | grep "$UNIQUE")" KEY_value="${KEY_grep##*=}" set_var $i "$KEY_value" done [ -d "$KEY_DIR" ] || up23_fail_upgrade "Cannot find CURRENT PKI KEY_DIR: $KEY_DIR" up23_verbose "> OK" up23_verbose " Current CURRENT PKI vars uses PKI in: $KEY_DIR" } #=> up23_verify_current_pki () # shellcheck disable=SC2154 up23_verify_current_ca () { up23_verbose "> Find CA .." # $KEY_DIR is assigned in up23_verify_current_pki () [ -f "$KEY_DIR/ca.crt" ] \ || up23_fail_upgrade "Cannot find current ca.crt: $KEY_DIR/ca.crt" up23_verbose "> OK" # If CA is already verified then return in_file="$KEY_DIR/ca.crt" [ "$CURRENT_CA_IS_VERIFIED" = "$in_file" ] && return 0 format="x509" # Current CA is unverified # Extract the current CA details name_opts="utf8,sep_multiline,space_eq,lname,align" CA_SUBJECT="$( easyrsa_openssl $format -in "$in_file" -subject -noout \ -nameopt "$name_opts" )" # Extract individual elements CA_countryName="$(printf "%s\n" "$CA_SUBJECT" \ | grep countryName | sed "s\`^.*=\ \`\`g")" CA_stateOrProvinceName="$(printf "%s\n" "$CA_SUBJECT" \ | grep stateOrProvinceName | sed "s\`^.*=\ \`\`g")" CA_localityName="$(printf "%s\n" "$CA_SUBJECT" \ | grep localityName | sed "s\`^.*=\ \`\`g")" CA_organizationName="$(printf "%s\n" "$CA_SUBJECT" \ | grep organizationName | sed "s\`^.*=\ \`\`g")" CA_organizationalUnitName="$(printf "%s\n" "$CA_SUBJECT" \ | grep organizationalUnitName | sed "s\`^.*=\ \`\`g")" CA_emailAddress="$(printf "%s\n" "$CA_SUBJECT" \ | grep emailAddress | sed "s\`^.*=\ \`\`g")" # Match the current CA elements to the vars file settings CA_vars_match=1 [ "$CA_countryName" = "$KEY_COUNTRY" ] || CA_vars_match=0 [ "$CA_stateOrProvinceName" = "$KEY_PROVINCE" ] || CA_vars_match=0 [ "$CA_localityName" = "$KEY_CITY" ] || CA_vars_match=0 [ "$CA_organizationName" = "$KEY_ORG" ] || CA_vars_match=0 [ "$CA_organizationalUnitName" = "$KEY_OU" ] || CA_vars_match=0 [ "$CA_emailAddress" = "$KEY_EMAIL" ] || CA_vars_match=0 if [ "$CA_vars_match" -eq 1 ] then CURRENT_CA_IS_VERIFIED="partially" else warn "CA certificate does not match vars file settings" fi opts="-certopt no_pubkey,no_sigdump" if [ ! "$EASYRSA_BATCH" ] then up23_show_current_ca elif [ "$VERBOSE" ] then up23_show_current_ca fi confirm "* Confirm CA shown above is correct: " "yes" \ "Found current CA at: $KEY_DIR/ca.crt" CURRENT_CA_IS_VERIFIED="$in_file" } #=> up23_verify_current_ca () up23_show_current_ca () { name_opts="utf8,sep_multiline,space_eq,lname,align" printf "%s\n" "-------------------------------------------------------------------------" # $opts is always set here # shellcheck disable=SC2086 # Ignore unquoted variables easyrsa_openssl $format -in "$in_file" -noout -text \ -nameopt "$name_opts" $opts || die "\ OpenSSL failure to process the input CA certificate: $in_file" printf "%s\n" "-------------------------------------------------------------------------" } #=> up23_show_current_ca () up23_backup_current_pki () { up23_verbose "> Backup current PKI .." mkdir -p "$EASYRSA_SAFE_PKI" \ || up23_fail_upgrade "Failed to create safe PKI dir: $EASYRSA_SAFE_PKI" cp -r "$KEY_DIR" "$EASYRSA_SAFE_PKI" \ || up23_fail_upgrade "Failed to copy $KEY_DIR to $EASYRSA_SAFE_PKI" # EASYRSA_VER2_VARSFILE is either version 2 *nix ./vars or Win vars.bat cp "$EASYRSA_VER2_VARSFILE" "$EASYRSA_SAFE_PKI" \ || up23_fail_upgrade "Failed to copy $EASYRSA_VER2_VARSFILE to EASYRSA_SAFE_PKI" up23_verbose "> OK" up23_verbose " Current PKI backup created in: $EASYRSA_SAFE_PKI" } #=> up23_backup_current_pki () up23_create_new_pki () { # Dirs: renewed and revoked are created when used. up23_verbose "> Create NEW PKI .." up23_verbose ">> Create NEW PKI dirs .." for i in private reqs issued certs_by_serial do mkdir -p "$EASYRSA_PKI/$i" \ || up23_fail_upgrade "Failed to Create NEW PKI dir: $EASYRSA_PKI/$i" done up23_verbose ">> OK" up23_verbose ">> Copy database to NEW PKI .." # Failure for these is not optional # Files ignored: index.txt.old serial.old for i in index.txt serial ca.crt index.txt.attr do cp "$KEY_DIR/$i" "$EASYRSA_PKI" \ || up23_fail_upgrade "Failed to copy $KEY_DIR/$i to $EASYRSA_PKI" done up23_verbose ">> OK" up23_verbose ">> Copy current PKI to NEW PKI .." for i in "csr.reqs" "pem.certs_by_serial" "crt.issued" "key.private" \ "p12.private" "p8.private" "p7b.issued" do FILE_EXT="${i%%.*}" DEST_DIR="${i##*.}" if ls "$KEY_DIR/"*".$FILE_EXT" > /dev/null 2>&1; then cp "$KEY_DIR/"*".$FILE_EXT" "$EASYRSA_PKI/$DEST_DIR" \ || up23_fail_upgrade "Failed to copy .$FILE_EXT" else up23_verbose " Note: No .$FILE_EXT files found" fi done up23_verbose ">> OK" up23_verbose "> OK" # Todo: CRL - Or generate a new CRL on completion up23_verbose " New PKI created in: $EASYRSA_PKI" } #=> up23_create_new_pki () up23_upgrade_ca () { [ -d "$EASYRSA_PKI" ] || return 0 up23_verbose "> Confirm that index.txt.attr exists and 'unique_subject = no'" if [ -f "$EASYRSA_PKI/index.txt.attr" ] then if grep -q 'unique_subject = no' "$EASYRSA_PKI/index.txt.attr" then # If index.txt.attr exists and "unique_suject = no" then do nothing return 0 fi else # If index.txt.attr does not exists then do nothing return 0 fi # Otherwise this is required for all easyrsa v3 #confirm "Set 'unique_subject = no' in index.txt.attr for your current CA: " \ #"yes" "This version of easyrsa requires that 'unique_subject = no' is set correctly" printf "%s\n" "unique_subject = no" > "$EASYRSA_PKI/index.txt.attr" up23_verbose "> OK" up23_verbose " Upgraded index.txt.attr to v306+" } #=> up23_upgrade_index_txt_attr () up23_create_openssl_cnf () { up23_verbose "> OpenSSL config .." EASYRSA_PKI_SSL_CNFFILE="$EASYRSA_PKI/openssl-easyrsa.cnf" EASYRSA_PKI_SAFE_CNFFILE="$EASYRSA_PKI/safessl-easyrsa.cnf" cp "$EASYRSA_SSL_CNFFILE" "$EASYRSA_PKI_SSL_CNFFILE" \ || up23_fail_upgrade "create $EASYRSA_PKI_SSL_CNFFILE" up23_verbose "> OK" up23_verbose " New OpenSSL config file created in: $EASYRSA_PKI_SSL_CNFFILE" # Create secure session # Because the upgrade runs twice, once as a test and then for real # secured_session must be cleared to avoid overload error #[ "$secured_session" ] && unset -v secured_session #up23_verbose "> Create secure session" #secure_session || die "up23_create_openssl_cnf - secure_session failed." #up23_verbose "> OK" #up23_verbose " secure session: $secured_session" # Create $EASYRSA_PKI/safessl-easyrsa.cnf easyrsa_openssl makesafeconf if [ -f "$EASYRSA_PKI_SAFE_CNFFILE" ] then up23_verbose " New SafeSSL config file created in: $EASYRSA_PKI_SAFE_CNFFILE" else up23_verbose " FAILED to create New SafeSSL config file in: $EASYRSA_PKI_SAFE_CNFFILE" fi } #=> up23_create_openssl_cnf () up23_move_easyrsa2_programs () { # These files may not exist here up23_verbose "> Move easyrsa2 programs to SAFE PKI .." for i in build-ca build-dh build-inter build-key build-key-pass \ build-key-pkcs12 build-key-server build-req build-req-pass \ clean-all inherit-inter list-crl pkitool revoke-full sign-req \ whichopensslcnf build-ca-pass build-key-server-pass init-config \ make-crl revoke-crt openssl-0.9.6.cnf openssl-0.9.8.cnf \ openssl-1.0.0.cnf openssl.cnf README.txt index.txt.start \ vars.bat.sample serial.start do # Although unlikely, both files could exist # EG: ./build-ca and ./build-ca.bat NIX_FILE="$EASYRSA/$i" WIN_FILE="$EASYRSA/$i.bat" if [ -f "$NIX_FILE" ] then cp "$NIX_FILE" "$EASYRSA_SAFE_PKI" \ || up23_fail_upgrade "copy $NIX_FILE $EASYRSA_SAFE_PKI" fi if [ -f "$WIN_FILE" ] then cp "$WIN_FILE" "$EASYRSA_SAFE_PKI" \ || up23_fail_upgrade "copy $WIN_FILE $EASYRSA_SAFE_PKI" fi if [ ! -f "$NIX_FILE" ] && [ ! -f "$WIN_FILE" ] then up23_verbose "File does not exist, ignoring: $i(.bat)" fi # These files are not removed on TEST run [ "$NOSAVE" -eq 1 ] && rm -f "$NIX_FILE" "$WIN_FILE" done up23_verbose "> OK" up23_verbose " Easyrsa2 programs successfully moved to: $EASYRSA_SAFE_PKI" } #=> up23_move_easyrsa2_programs () # shellcheck disable=SC2154 up23_build_v3_vars () { up23_verbose "> Build v3 vars file .." EASYRSA_EXT="easyrsa-upgrade-23" EASYRSA_VARSV2_TMP="$EASYRSA/vars-v2.tmp.$EASYRSA_EXT" rm -f "$EASYRSA_VARSV2_TMP" EASYRSA_VARSV3_TMP="$EASYRSA/vars-v3.tmp.$EASYRSA_EXT" rm -f "$EASYRSA_VARSV3_TMP" EASYRSA_VARSV3_NEW="$EASYRSA/vars-v3.new.$EASYRSA_EXT" rm -f "$EASYRSA_VARSV3_NEW" EASYRSA_VARSV3_WRN="$EASYRSA/vars-v3.wrn.$EASYRSA_EXT" rm -f "$EASYRSA_VARSV3_WRN" printf "%s\n" "\ ########################++++++++++######################### ### ### ### WARNING: THIS FILE WAS AUTOMATICALLY GENERATED ### ### ALL SETTINGS ARE AT THE END OF THE FILE ### ### ### ########################++++++++++######################### " > "$EASYRSA_VARSV3_WRN" || up23_fail_upgrade "Failed to create $EASYRSA_VARSV3_WRN" # Create vars v3 temp file from sourced vars v2 key variables { printf "%s\n" "set_var EASYRSA_KEY_SIZE $KEY_SIZE" printf "%s\n" "set_var EASYRSA_REQ_COUNTRY \"$KEY_COUNTRY\"" printf "%s\n" "set_var EASYRSA_REQ_PROVINCE \"$KEY_PROVINCE\"" printf "%s\n" "set_var EASYRSA_REQ_CITY \"$KEY_CITY\"" printf "%s\n" "set_var EASYRSA_REQ_ORG \"$KEY_ORG\"" printf "%s\n" "set_var EASYRSA_REQ_EMAIL \"$KEY_EMAIL\"" printf "%s\n" "set_var EASYRSA_REQ_OU \"$KEY_OU\"" printf "%s\n" 'set_var EASYRSA_NS_SUPPORT "yes"' printf "%s\n" 'set_var EASYRSA_DN "org"' printf "%s\n" 'set_var EASYRSA_RAND_SN "no"' printf "%s\n" "" } > "$EASYRSA_VARSV3_TMP" \ || up23_fail_upgrade "Failed to create $EASYRSA_VARSV3_TMP" # cat temp files into new v3 vars cat "$EASYRSA_VARSV3_WRN" "$EASYRSA_VARSV3_EXMP" "$EASYRSA_VARSV3_TMP" \ > "$EASYRSA_VARSV3_NEW" \ || up23_fail_upgrade "Failed to create $EASYRSA_VARSV3_NEW" # This file must be created and restored at the end of TEST # for the REAL update to to succeed EASYRSA_VARS_LIVEBKP="$EASYRSA_TARGET_VARSFILE.livebackup" cp "$EASYRSA_VER2_VARSFILE" "$EASYRSA_VARS_LIVEBKP" \ || up23_fail_upgrade "Failed to create $EASYRSA_VARS_LIVEBKP" rm -f "$EASYRSA_VER2_VARSFILE" # "$EASYRSA_TARGET_VARSFILE" is always $EASYRSA/vars cp "$EASYRSA_VARSV3_NEW" "$EASYRSA_TARGET_VARSFILE" \ || up23_fail_upgrade "copy $EASYRSA_VARSV3_NEW to $EASYRSA_TARGET_VARSFILE" # Delete temp files rm -f "$EASYRSA_VARSV2_TMP" "$EASYRSA_VARSV3_TMP" \ "$EASYRSA_VARSV3_NEW" "$EASYRSA_VARSV3_WRN" up23_verbose "> OK" up23_verbose " New v3 vars file created in: $EASYRSA_TARGET_VARSFILE" } #=> up23_build_v3_vars () # shellcheck disable=SC2154 up23_do_upgrade_23 () { up23_verbose "============================================================================" up23_verbose "Begin ** $1 ** upgrade process .." up23_verbose "" up23_verbose "Easyrsa upgrade version: $EASYRSA_UPGRADE_23" up23_verbose "" up23_verify_new_pki up23_create_new_pki up23_create_openssl_cnf up23_verify_current_pki up23_verify_current_ca up23_backup_current_pki up23_upgrade_ca up23_move_easyrsa2_programs up23_build_v3_vars if [ "$NOSAVE" -eq 0 ] then # Must stay in this order # New created dirs: EASYRSA_NEW_PKI and EASYRSA_SAFE_PKI rm -rf "$EASYRSA_NEW_PKI" rm -rf "$EASYRSA_SAFE_PKI" # EASYRSA_TARGET_VARSFILE is always the new created v3 vars # Need to know if this fails rm "$EASYRSA_TARGET_VARSFILE" \ || up23_fail_upgrade "remove new vars file: $EASYRSA_TARGET_VARSFILE" # EASYRSA_VER2_VARSFILE is either v2 *nix ./vars or Win vars.bat # Need this dance because v2 vars is same name as v3 vars above cp "$EASYRSA_VARS_LIVEBKP" "$EASYRSA_VER2_VARSFILE" fi rm -f "$EASYRSA_VARS_LIVEBKP" } #= up23_do_upgrade_23 () up23_manage_upgrade_23 () { EASYRSA_UPGRADE_VERSION="v1.0a (2020/01/08)" EASYRSA_UPGRADE_TYPE="$1" EASYRSA_FOUND_VARS=0 # Verify all existing versions of vars/vars.bat if [ -f "$vars" ] then if grep -q 'Complain if a user tries to do this:' "$vars" then EASYRSA_FOUND_VARS=1 EASYRSA_VARS_IS_VER3=1 fi # Easyrsa v3 does not use NOR allow use of `export`. if grep -q 'export' "$vars" then EASYRSA_FOUND_VARS=1 EASYRSA_VARS_IS_VER2=1 EASYRSA_VER2_VARSFILE="$vars" EASYRSA_TARGET_VARSFILE="$vars" fi fi if [ -f "$EASYRSA/vars.bat" ] then EASYRSA_FOUND_VARS=1 EASYRSA_VARS_IS_WIN2=1 EASYRSA_VER2_VARSFILE="$EASYRSA/vars.bat" EASYRSA_TARGET_VARSFILE="$EASYRSA/vars" fi if [ $EASYRSA_FOUND_VARS -ne 1 ]; then die "vars file not found" fi # Only allow specific vars/vars.bat to exist if [ "$EASYRSA_VARS_IS_VER3" ] && [ "$EASYRSA_VARS_IS_VER2" ] then die "Verify your current vars file, v3 cannot use 'export'." fi if [ "$EASYRSA_VARS_IS_VER3" ] && [ "$EASYRSA_VARS_IS_WIN2" ] then die "Verify your current vars/vars.bat file, cannot have both." fi if [ "$EASYRSA_VARS_IS_VER2" ] && [ "$EASYRSA_VARS_IS_WIN2" ] then die "Verify your current vars/vars.bat file, cannot have both." fi # Die on invalid upgrade type or environment if [ "$EASYRSA_UPGRADE_TYPE" = "ca" ] then if [ "$EASYRSA_VARS_IS_VER3" ] then # v3 ensure index.txt.attr "unique_subject = no" up23_upgrade_ca unset -v EASYRSA_BATCH notice "Your CA is fully up to date." return 0 else die "Only v3 PKI CA can be upgraded." fi fi if [ "$EASYRSA_UPGRADE_TYPE" = "pki" ] then if [ "$EASYRSA_VARS_IS_VER3" ] then unset -v EASYRSA_BATCH notice "Your PKI is fully up to date." return 0 fi else user_error "upgrade type must be 'pki' or 'ca'." fi # PKI is potentially suitable for upgrade warn " ========================================================================= * WARNING * Found settings from EasyRSA-v2 which are not compatible with EasyRSA-v3. Before you can continue, EasyRSA must upgrade your settings and PKI. * Found EASYRSA and vars file: $EASYRSA $EASYRSA_VER2_VARSFILE : Further info: * https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade Easyrsa upgrade version: $EASYRSA_UPGRADE_VERSION ========================================================================= " # Test upgrade NOSAVE=0 confirm "* EasyRSA **TEST** upgrade (Changes will NOT be written): " "yes" " This upgrade will TEST that the upgrade works BEFORE making any changes." up23_do_upgrade_23 "TEST" notice " ========================================================================= * NOTICE * EasyRSA upgrade **TEST** has successfully completed. " # Upgrade for REAL NOSAVE=1 confirm "* EasyRSA **REAL** upgrade (Changes WILL be written): " "yes" " ========================================================================= * WARNING * Run REAL upgrade: Answer yes (Once completed you will have a version 3 PKI) Terminate upgrade: Answer no (No changes have been made to your current PKI) " confirm "* Confirm **REAL** upgrade (Changes will be written): " "yes" " ========================================================================= * SECOND WARNING * This upgrade will permanently write changes to your PKI ! (With full backup backout) " up23_do_upgrade_23 "REAL" notice " ========================================================================= * NOTICE * Your settings and PKI have been successfully upgraded to EasyRSA version3 A backup of your current PKI is here: $EASYRSA_SAFE_PKI * IMPORTANT NOTICE * 1. YOU MUST VERIFY THAT YOUR NEW ./vars FILE IS SETUP CORRECTLY 2. IF YOU ARE USING WINDOWS YOU MUST ENSURE THAT openssl IS CORRECTLY DEFINED IN ./vars (example follows) # # This sample is in Windows syntax -- edit it for your path if not using PATH: # set_var EASYRSA_OPENSSL \"C:/Program Files/OpenSSL-Win32/bin/openssl.exe\" # # Alternate location (Note: Forward slash '/' is correct for Windpws): # set_var EASYRSA_OPENSSL \"C:/Program Files/Openvpn/bin/openssl.exe\" # 3. Finally, you can verify that easyrsa works by using these two commands: ./easyrsa show-ca (Verify that your CA is intact and correct) ./easyrsa gen-crl ((re)-generate a CRL file) Further info: * https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade" up23_verbose " * UPGRADE COMPLETED SUCCESSFULLY * " return 0 } # => up23_manage_upgrade_23 () print_version() { ssl_version="$( OPENSSL_CONF=/dev/null \ "${EASYRSA_OPENSSL:-openssl}" version )" cat << VERSION_TEXT EasyRSA Version Information Version: $EASYRSA_version Generated: Fri Oct 13 17:27:51 CDT 2023 SSL Lib: ${ssl_version:-undefined} Git Commit: 3c233d279d43e419b0529411ee62bba7a08f0c0f Source Repo: https://github.com/OpenVPN/easy-rsa VERSION_TEXT } # => print_version () ######################################## # Invocation entry point: EASYRSA_version="3.1.7" NL=' ' # Be secure with a restrictive umask [ "$EASYRSA_NO_UMASK" ] || umask "${EASYRSA_UMASK:=077}" # Register cleanup on EXIT trap 'cleanup $?' EXIT # When SIGHUP, SIGINT, SIGQUIT, SIGABRT and SIGTERM, # explicitly exit to signal EXIT (non-bash shells) trap "exit 1" 1 trap "exit 2" 2 trap "exit 3" 3 trap "exit 6" 6 trap "exit 14" 15 # Get host details - No configurable input allowed detect_host # Initialisation requirements unset -v \ verify_ssl_lib_ok \ secured_session \ working_safe_ssl_conf working_safe_org_conf \ makesafeconf \ alias_days \ prohibit_no_pass \ invalid_vars \ no_new_vars user_vars_true \ do_build_full error_build_full_cleanup \ internal_batch \ easyrsa_exit_with_error error_info # Used by build-ca->cleanup to restore prompt # after user interrupt when using manual password prompt_restore=0 # Parse options while :; do # Reset per pass flags unset -v opt val \ is_empty empty_ok number_only zero_allowed # Separate option from value: opt="${1%%=*}" val="${1#*=}" # Empty values are not allowed unless expected # eg: '--batch' [ "$opt" = "$val" ] && is_empty=1 # eg: '--pki-dir=' [ "$val" ] || is_empty=1 case "$opt" in --days) number_only=1 # Set the appropriate date variable # when called by command later alias_days="$val" ;; --startdate) export EASYRSA_START_DATE="$val" ;; --enddate) export EASYRSA_END_DATE="$val" ;; --pki-dir|--pki) export EASYRSA_PKI="$val" ;; --tmp-dir) export EASYRSA_TEMP_DIR="$val" ;; --ssl-conf) export EASYRSA_SSL_CONF="$val" ;; --keep-tmp) export EASYRSA_KEEP_TEMP="$val" ;; --use-algo) export EASYRSA_ALGO="$val" ;; --keysize) number_only=1 export EASYRSA_KEY_SIZE="$val" ;; --curve) export EASYRSA_CURVE="$val" ;; --dn-mode) export EASYRSA_DN="$val" ;; --req-cn) export EASYRSA_REQ_CN="$val" ;; --digest) export EASYRSA_DIGEST="$val" ;; --req-c) empty_ok=1 export EASYRSA_REQ_COUNTRY="$val" ;; --req-st) empty_ok=1 export EASYRSA_REQ_PROVINCE="$val" ;; --req-city) empty_ok=1 export EASYRSA_REQ_CITY="$val" ;; --req-org) empty_ok=1 export EASYRSA_REQ_ORG="$val" ;; --req-email) empty_ok=1 export EASYRSA_REQ_EMAIL="$val" ;; --req-ou) empty_ok=1 export EASYRSA_REQ_OU="$val" ;; --req-serial) empty_ok=1 export EASYRSA_REQ_SERIAL="$val" ;; --ns-cert) empty_ok=1 [ "$is_empty" ] && unset -v val export EASYRSA_NS_SUPPORT="${val:-yes}" ;; --ns-comment) empty_ok=1 export EASYRSA_NS_COMMENT="$val" ;; --batch) empty_ok=1 export EASYRSA_BATCH=1 ;; -s|--silent) empty_ok=1 export EASYRSA_SILENT=1 ;; --sbatch|--silent-batch) empty_ok=1 export EASYRSA_SILENT=1 export EASYRSA_BATCH=1 ;; --verbose) empty_ok=1 export EASYRSA_VERBOSE=1 ;; --days-margin) # ONLY ALLOWED use by status reports number_only=1 export EASYRSA_iso_8601_MARGIN="$val" ;; -S|--silent-ssl) empty_ok=1 export EASYRSA_SILENT_SSL=1 # This will probably be need #save_EASYRSA_SILENT_SSL=1 ;; --force-safe-ssl) empty_ok=1 export EASYRSA_FORCE_SAFE_SSL=1 ;; --nopass|--no-pass) empty_ok=1 export EASYRSA_NO_PASS=1 ;; --passin) export EASYRSA_PASSIN="$val" ;; --passout) export EASYRSA_PASSOUT="$val" ;; --raw-ca) empty_ok=1 export EASYRSA_RAW_CA=1 ;; --notext|--no-text) empty_ok=1 export EASYRSA_NO_TEXT=1 ;; --subca-len) number_only=1 zero_allowed=1 export EASYRSA_SUBCA_LEN="$val" ;; --vars) user_vars_true=1 export EASYRSA_VARS_FILE="$val" ;; --copy-ext) empty_ok=1 export EASYRSA_CP_EXT=1 ;; --subject-alt-name|--san) export EASYRSA_EXTRA_EXTS="\ $EASYRSA_EXTRA_EXTS subjectAltName = $val" ;; --version) shift "$#" set -- "$@" "version" break ;; # Unsupported options --fix-offset) user_error "Option $opt is not supported. Use options --startdate and --enddate for fixed dates." ;; -*) user_error "\ Unknown option '$opt'. Run 'easyrsa help options' for option help." ;; *) break esac # fatal error when no value was provided if [ "$is_empty" ]; then [ "$empty_ok" ] || \ user_error "Missing value to option: $opt" fi # fatal error when a number is expected but not provided if [ "$number_only" ]; then case "$val" in (0) # Allow zero only [ "$zero_allowed" ] || \ user_error "$opt - Number expected: '$val'" ;; (*[!1234567890]*|0*) user_error "$opt - Number expected: '$val'" esac fi shift done # Set cmd now # vars_setup needs to know if this is init-pki cmd="$1" [ "$1" ] && shift # scrape off command # Establish PKI and CA initialisation requirements # This avoids unnecessary warnings and notices case "$cmd" in ''|help|-h|--help|--usage|version|upgrade|show-host) unset -v require_pki require_ca ignore_vars=1 ;; init-pki|clean-all) unset -v require_pki require_ca ;; *) require_pki=1 case "$cmd" in gen-req|gen-dh|build-ca|show-req| \ make-safe-ssl|export-p*|inline) unset -v require_ca ;; *) require_ca=1 esac esac # Run these commands with NO setup case "$cmd" in make-vars) create_vars_example cleanup ok ;; esac # Intelligent env-var detection and auto-loading: # Select vars file as EASYRSA_VARS_FILE select_vars # source the vars file source_vars "$EASYRSA_VARS_FILE" # then set defaults default_vars # Check for unexpected changes to EASYRSA or EASYRSA_PKI # This will be resolved in v3.2.0 # https://github.com/OpenVPN/easy-rsa/issues/1006 validate_default_vars # Check for conflicting input options mutual_exclusions # Hand off to the function responsible # ONLY verify_working_env() for valid commands case "$cmd" in init-pki|clean-all) verify_working_env init_pki "$@" ;; build-ca) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_CA_EXPIRE="$alias_days" build_ca "$@" ;; gen-dh) verify_working_env gen_dh ;; gen-req) verify_working_env gen_req "$@" ;; sign|sign-req) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_CERT_EXPIRE="$alias_days" sign_req "$@" ;; build-client-full) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_CERT_EXPIRE="$alias_days" build_full client "$@" ;; build-server-full) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_CERT_EXPIRE="$alias_days" build_full server "$@" ;; build-serverClient-full) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_CERT_EXPIRE="$alias_days" build_full serverClient "$@" ;; gen-crl) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_CRL_DAYS="$alias_days" gen_crl ;; revoke) verify_working_env revoke "$@" ;; revoke-renewed) verify_working_env revoke_renewed "$@" ;; renew) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_CERT_EXPIRE="$alias_days" renew "$@" ;; rewind-renew) verify_working_env rewind_renew "$@" ;; rebuild) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_CERT_EXPIRE="$alias_days" rebuild "$@" ;; import-req) verify_working_env import_req "$@" ;; inline) verify_working_env inline_creds "$@" || \ easyrsa_exit_with_error=1 ;; export-p12) verify_working_env export_pkcs p12 "$@" ;; export-p7) verify_working_env export_pkcs p7 "$@" ;; export-p8) verify_working_env export_pkcs p8 "$@" ;; export-p1) verify_working_env export_pkcs p1 "$@" ;; set-rsa-pass) verify_working_env set_pass_legacy rsa "$@" ;; set-ec-pass) verify_working_env set_pass_legacy ec "$@" ;; set-pass|set-ed-pass) verify_working_env set_pass "$@" ;; update-db) verify_working_env update_db ;; show-req) verify_working_env show req "$@" ;; show-cert) verify_working_env show cert "$@" ;; show-crl) verify_working_env show crl crl ;; show-ca) verify_working_env show_ca "$@" ;; show-expire) verify_working_env [ -z "$alias_days" ] || \ export EASYRSA_PRE_EXPIRY_WINDOW="$alias_days" status expire "$@" ;; show-revoke) verify_working_env status revoke "$@" ;; show-renew) verify_working_env status renew "$@" ;; show-host) verify_working_env show_host "$@" ;; verify|verify-cert) verify_working_env # Called with --batch, this will return error # when the certificate fails verification. # Therefore, on error, exit with error. verify_cert "$@" || \ easyrsa_exit_with_error=1 ;; mss|make-safe-ssl) verify_working_env make_safe_ssl "$@" ;; serial|check-serial) verify_working_env # Called with --batch, this will return error # when the serial number is not unique. # Therefore, on error, exit with error. check_serial_unique "$@" || \ easyrsa_exit_with_error=1 ;; display-dn) verify_working_env display_dn "$@" ;; display-san) verify_working_env display_san "$@" ;; default-san) verify_working_env default_server_san "$@" ;; x509-eku) verify_working_env ssl_cert_x509v3_eku "$@" ;; upgrade) verify_working_env up23_manage_upgrade_23 "$@" ;; ""|help|-h|--help|--usage) verify_working_env cmd_help "$1" ;; version) print_version ;; *) user_error "\ Unknown command '$cmd'. Run without commands for usage help." esac # Check for untrapped errors # shellcheck disable=SC2181 if [ $? = 0 ]; then # Do 'cleanup ok' on successful completion #print "mktemp_counter: $mktemp_counter uses" cleanup ok fi # Otherwise, exit with error print "Untrapped error detected!" cleanup # vim: ft=sh nu ai sw=8 ts=8 noet EasyRSA-3.1.7/doc/000775 000765 000024 00000000000 14512342147 014177 5ustar00ecriststaff000000 000000 EasyRSA-3.1.7/vars.example000664 000765 000024 00000021575 14512342147 015774 0ustar00ecriststaff000000 000000 # Easy-RSA 3 parameter settings # NOTE: If you installed Easy-RSA from your package manager, do not edit # this file in place -- instead, you should copy the entire easy-rsa directory # to another location so future upgrades do not wipe out your changes. # HOW TO USE THIS FILE # # vars.example contains built-in examples to Easy-RSA settings. You MUST name # this file "vars" if you want it to be used as a configuration file. If you # do not, it WILL NOT be automatically read when you call easyrsa commands. # # It is not necessary to use this config file unless you wish to change # operational defaults. These defaults should be fine for many uses without # the need to copy and edit the "vars" file. # # All of the editable settings are shown commented and start with the command # "set_var" -- this means any set_var command that is uncommented has been # modified by the user. If you are happy with a default, there is no need to # define the value to its default. # NOTES FOR WINDOWS USERS # # Paths for Windows *MUST* use forward slashes, or optionally double-escaped # backslashes (single forward slashes are recommended.) This means your path # to the openssl binary might look like this: # "C:/Program Files/OpenSSL-Win32/bin/openssl.exe" # A little housekeeping: DO NOT EDIT THIS SECTION # # Easy-RSA 3.x does not source into the environment directly. # Complain if a user tries to do this: if [ -z "$EASYRSA_CALLER" ]; then echo "You appear to be sourcing an Easy-RSA *vars* file. This is" >&2 echo "no longer necessary and is disallowed. See the section called" >&2 echo "*How to use this file* near the top comments for more details." >&2 return 1 fi # DO YOUR EDITS BELOW THIS POINT # This variable is used as the base location of configuration files needed by # easyrsa. More specific variables for specific files (eg: EASYRSA_SSL_CONF) # may override this default. # # The default value of this variable is the location of the easyrsa script # itself, which is also where the configuration files are located in the # easy-rsa tree. # #set_var EASYRSA "${0%/*}" # If your OpenSSL command is not in the system PATH, you will need to define # the path here. Normally this means a full path to the executable, otherwise # you could have left it undefined here and the shown default would be used. # # Windows users, remember to use paths with forward-slashes (or escaped # back-slashes.) Windows users should declare the full path to the openssl # binary here if it is not in their system PATH. # #set_var EASYRSA_OPENSSL "openssl" # # This sample is in Windows syntax -- edit it for your path if not using PATH: #set_var EASYRSA_OPENSSL "C:/Program Files/OpenSSL-Win32/bin/openssl.exe" # Edit this variable to point to your soon-to-be-created key directory. # By default, this will be "$PWD/pki" (ie: the "pki" subdirectory of the # directory you are currently in). # # WARNING: init-pki will do a rm -rf on this directory so make sure you define # it correctly! Interactive mode will prompt before acting. # #set_var EASYRSA_PKI "$PWD/pki" # Define directory for temporary subdirectories. # #set_var EASYRSA_TEMP_DIR "$EASYRSA_PKI" # Define X509 DN mode. # # This is used to adjust which elements are included in the Subject field # as the DN ("Distinguished Name"). Note that in 'cn_only' mode the # Organizational fields, listed further below, are not used. # # Choices are: # cn_only - Use just a commonName value. # org - Use the "traditional" format: # Country/Province/City/Org/Org.Unit/email/commonName # #set_var EASYRSA_DN "cn_only" # Organizational fields (used with "org" mode and ignored in "cn_only" mode). # These are the default values for fields which will be placed in the # certificate. Do not leave any of these fields blank, although interactively # you may omit any specific field by typing the "." symbol (not valid for # email). # # NOTE: The following characters are not supported # in these "Organizational fields" by Easy-RSA: # back-tick (`) # #set_var EASYRSA_REQ_COUNTRY "US" #set_var EASYRSA_REQ_PROVINCE "California" #set_var EASYRSA_REQ_CITY "San Francisco" #set_var EASYRSA_REQ_ORG "Copyleft Certificate Co" #set_var EASYRSA_REQ_EMAIL "me@example.net" #set_var EASYRSA_REQ_OU "My Organizational Unit" # Preserve the Distinguished Name field order # of the certificate signing request # *Only* effective in --dn-mode=org # #set_var EASYRSA_PRESERVE_DN 1 # Set no password mode - This will create the entire PKI without passwords. # This can be better managed by choosing which entity private keys should be # encrypted with the following command line options: # Global option '--no-pass' or command option 'nopass'. # #set_var EASYRSA_NO_PASS 1 # Choose a size in bits for your keypairs. The recommended value is 2048. # Using 2048-bit keys is considered more than sufficient for many years into # the future. Larger keysizes will slow down TLS negotiation and make key/DH # param generation take much longer. Values up to 4096 should be accepted by # most software. Only used when the crypto alg is rsa, see below. # #set_var EASYRSA_KEY_SIZE 2048 # The default crypto mode is rsa; ec can enable elliptic curve support. # Note that not all software supports ECC, so use care when enabling it. # Choices for crypto alg are: (each in lower-case) # * rsa # * ec # * ed # #set_var EASYRSA_ALGO rsa # Define the named curve, used in ec & ed modes: # #set_var EASYRSA_CURVE secp384r1 # In how many days should the root CA key expire? # #set_var EASYRSA_CA_EXPIRE 3650 # In how many days should certificates expire? # #set_var EASYRSA_CERT_EXPIRE 825 # How many days until the next CRL publish date? Note that the CRL can still # be parsed after this timeframe passes. It is only used for an expected next # publication date. # #set_var EASYRSA_CRL_DAYS 180 # Random serial numbers by default. # Set to 'no' for the old incremental serial numbers. # #set_var EASYRSA_RAND_SN "yes" # Cut-off window for checking expiring certificates. # #set_var EASYRSA_PRE_EXPIRY_WINDOW 90 # Support deprecated "Netscape" extensions? (choices "yes" or "no"). # The default is "no", to discourage use of deprecated extensions. # If you require this feature to use with --ns-cert-type, set this to "yes". # This support should be replaced with the more modern --remote-cert-tls # feature. If you do not use --ns-cert-type in your configs, it is safe, # and recommended, to leave this defined to "no". # When set to "yes", server-signed certs get the nsCertType=server attribute # and also get any NS_COMMENT defined below in the nsComment field. # #set_var EASYRSA_NS_SUPPORT "no" # When NS_SUPPORT is set to "yes", this field is added as the nsComment field. # Set this blank to omit it. With NS_SUPPORT set to "no" this field is ignored. # #set_var EASYRSA_NS_COMMENT "Easy-RSA Generated Certificate" # !! # NOTE: ADVANCED OPTIONS BELOW THIS POINT # PLAY WITH THEM AT YOUR OWN RISK # !! # Broken shell command aliases: If you have a largely broken shell that is # missing any of these POSIX-required commands used by Easy-RSA, you will need # to define an alias to the proper path for the command. The symptom will be # some form of a "command not found" error from your shell. This means your # shell is BROKEN, but you can hack around it here if you really need. These # shown values are not defaults: it is up to you to know what you are doing if # you touch these. # #alias awk="/alt/bin/awk" #alias cat="/alt/bin/cat" # X509 extensions directory: # If you want to customize the X509 extensions used, set the directory to look # for extensions here. Each cert type you sign must have a matching filename, # and an optional file named "COMMON" is included first when present. Note that # when undefined here, default behaviour is to look in $EASYRSA_PKI first, then # fallback to $EASYRSA for the "x509-types" dir. You may override this # detection with an explicit dir here. # #set_var EASYRSA_EXT_DIR "$EASYRSA/x509-types" # Non-functional # If you want to generate KDC certificates, you need to set the realm here. # #set_var EASYRSA_KDC_REALM "CHANGEME.EXAMPLE.COM" # OpenSSL config file: # If you need to use a specific openssl config file, you can reference it here. # Normally this file is auto-detected from a file named openssl-easyrsa.cnf # from the EASYRSA_PKI or EASYRSA dir, in that order. NOTE that this file is # Easy-RSA specific and you cannot just use a standard config file, so this is # an advanced feature. # #set_var EASYRSA_SSL_CONF "$EASYRSA_PKI/openssl-easyrsa.cnf" # Cryptographic digest to use. # Do not change this default unless you understand the security implications. # Valid choices include: md5, sha1, sha256, sha224, sha384, sha512 # #set_var EASYRSA_DIGEST "sha256" # Batch mode. Leave this disabled unless you intend to call Easy-RSA explicitly # in batch mode without any user input, confirmation on dangerous operations, # or most output. Setting this to any non-blank string enables batch mode. # #set_var EASYRSA_BATCH "" EasyRSA-3.1.7/README.quickstart.md000664 000765 000024 00000006407 14512342147 017111 0ustar00ecriststaff000000 000000 Easy-RSA 3 Quickstart README ============================ This is a quickstart guide to using Easy-RSA version 3. Detailed help on usage and specific commands can be found by running ./easyrsa -h. Additional documentation can be found in the doc/ directory. If you're upgrading from the Easy-RSA 2.x series, there are Upgrade-Notes available, also under the doc/ path. Setup and signing the first request ----------------------------------- Here is a quick run-though of what needs to happen to start a new PKI and sign your first entity certificate: 1. Choose a system to act as your CA and create a new PKI and CA: ./easyrsa init-pki ./easyrsa build-ca 2. On the system that is requesting a certificate, init its own PKI and generate a keypair/request. Note that init-pki is used _only_ when this is done on a separate system (or at least a separate PKI dir.) This is the recommended procedure. If you are not using this recommended procedure, skip the next import-req step. ./easyrsa init-pki ./easyrsa gen-req EntityName 3. Transport the request (.req file) to the CA system and import it. The name given here is arbitrary and only used to name the request file. ./easyrsa import-req /tmp/path/to/import.req EntityName 4. Sign the request as the correct type. This example uses a client type: ./easyrsa sign-req client EntityName 5. Transport the newly signed certificate to the requesting entity. This entity may also need the CA cert (ca.crt) unless it had a prior copy. 6. The entity now has its own keypair, signed cert, and the CA. Signing subsequent requests --------------------------- Follow steps 2-6 above to generate subsequent keypairs and have the CA return signed certificates. Revoking certs and creating CRLs -------------------------------- This is a CA-specific task. To permanently revoke an issued certificate, provide the short name used during import: ./easyrsa revoke EntityName To create an updated CRL that contains all revoked certs up to that point: ./easyrsa gen-crl After generation, the CRL will need to be sent to systems that reference it. Generating Diffie-Hellman (DH) params ------------------------------------- After initializing a PKI, any entity can create DH params that needs them. This is normally only used by a TLS server. While the CA PKI can generate this, it makes more sense to do it on the server itself to avoid the need to send the files to another system after generation. DH params can be generated with: ./easyrsa gen-dh Showing details of requests or certs ------------------------------------ To show the details of a request or certificate by referencing the short EntityName, use one of the following commands. It is an error to call these without a matching file. ./easyrsa show-req EntityName ./easyrsa show-cert EntityName Changing private key passphrases -------------------------------- RSA and EC private keys can be re-encrypted so a new passphrase can be supplied with one of the following commands depending on the key type: ./easyrsa set-rsa-pass EntityName ./easyrsa set-ec-pass EntityName Optionally, the passphrase can be removed completely with the 'nopass' flag. Consult the command help for details. EasyRSA-3.1.7/mktemp.txt000664 000765 000024 00000002014 14512342147 015465 0ustar00ecriststaff000000 000000 Mktemp is distributed under the following ISC-style license: Copyright (c) 1996-1997, 2000-2001, 2008, 2010 Todd C. Miller Copyright (c) 1996, David Mazieres Copyright (c) 2008, Damien Miller Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. From https://www.mktemp.org/mktemp/license.html EasyRSA-3.1.7/doc/Intro-To-PKI.md000664 000765 000024 00000011473 14512342147 016623 0ustar00ecriststaff000000 000000 Introduction to PKI =================== This document is designed to give you a brief introduction into how a PKI, or Public Key Infrastructure, works. Terminology Used ---------------- To avoid confusion, the following terms will be used throughout the Easy-RSA documentation. Short forms may be substituted for longer forms as convenient. * **PKI**: Public Key Infrastructure. This describes the collection of files and associations between the CA, keypairs, requests, and certificates. * **CA**: Certificate Authority. This is the "master cert" at the root of a PKI. * **cert**: Certificate. A certificate is a request that has been signed by a CA. The certificate contains the public key, some details describing the cert itself, and a digital signature from the CA. * **request**: Certificate Request (optionally 'req'.) This is a request for a certificate that is then sent to a CA for signing. A request contains the desired cert information along with a digital signature from the private key. * **keypair**: A keypair is an asymmetric cryptographic pair of keys. These keys are split into two parts: the public and private keys. The public key is included in a request and certificate. The CA ------ The heart of a PKI is the CA, or Certificate Authority, and this is also the most security-sensitive. The CA private key is used to sign all issued certificates, so its security is critical in keeping the entire PKI safe. For this reason, it is highly recommended that the CA PKI structure be kept on a system dedicated for such secure usage; it is not a great idea to keep the CA PKI mixed in with one used to generate end-entity certificates, such as clients or servers (VPN or web servers.) To start a new PKI, the CA is first created on the secure environment. Depending on security needs, this could be managed under a locked down account, dedicated system, or even a completely offline system or using removable media to improve security (after all, you can't suffer an online break-in if your system or PKI is not online.) The exact steps to create a CA are described in a separate section. When creating a new CA, the CA keypair (private and public keys) are created, as well as the file structure necessary to support signing issued certificates. Once a CA has been created, it can receive certificate requests from end-entities. These entity certificates are issued to consumers of X509 certificates, such as a client or server of a VPN, web, or email system. The certificate requests and certificates are not security-sensitive, and can be transferred in whatever means convenient, such as email, flash drive, etc. For better security, it is a good idea to verify the received request matches the sender's copy, such as by verifying the expected checksum against the sender's original. Keypairs and requests --------------------- Individual end-entities do not need a full CA set up and will only need to create a keypair and associated certificate request. The private key is not used anywhere except on this entity, and should never leave that system. It is wise to secure this private key with a strong passphrase, because if lost or stolen the holder of the private key can make connections appearing as the certificate holder. Once a keypair is generated, the certificate request is created and digitally signed using the private key. This request will be sent to a CA for signing, and a signed certificate will be returned. How requests become certificates -------------------------------- After a CA signs the certificate request, a signed certificate is produced. In this step, the CA's private key is used to digitally sign the entity's public key so that any system trusting the CA certificate can implicitly trust the newly issued certificate. This signed certificate is then sent back to the requesting entity. The issued certificate is not security-sensitive and can be sent over plaintext transmission methods. Verifying an issued certificate ------------------------------- After 2 entities have created keypairs, sent their requests to the CA, and received a copy of their signed certificates and the CA's own certificate, they can mutually authenticate with one-another. This process does not require the 2 entities to have previously exchanged any kind of security information directly. During a TLS handshake each side of the connection presents their own cert chain to the remote end. Each side checks the validity of the cert received against their own copy of the CA cert. By trusting the CA root cert, the peer they are talking to can be authenticated. The remote end proves it "really is" the entity identified by the cert by signing a bit of data using its own private key. Only the holder of the private key is able to do this, allowing the remote end to verify the authenticity of the system being connected to. EasyRSA-3.1.7/doc/EasyRSA-Readme.md000664 000765 000024 00000022737 14512342147 017176 0ustar00ecriststaff000000 000000 Easy-RSA 3 Documentation Readme =============================== This document explains how Easy-RSA 3 and each of its assorted features work. If you are looking for a quickstart with less background or detail, an implementation-specific How-to or Readme may be available in this (the [`doc/`](./)) directory. Easy-RSA Overview ----------------- Easy-RSA is a utility for managing X.509 PKI, or Public Key Infrastructure. A PKI is based on the notion of trusting a particular authority to authenticate a remote peer; for more background on how PKI works, see the [Intro-To-PKI](Intro-To-PKI.md) document. The code is written in platform-neutral POSIX shell, allowing use on a wide range of host systems. The official Windows release also comes bundled with the programs necessary to use Easy-RSA. The shell code attempts to limit the number of external programs it depends on. Crypto-related tasks use openssl as the functional backend. Feature Highlights ------------------ Here's a non-exhaustive list of the more notable Easy-RSA features: * Easy-RSA is able to manage multiple PKIs, each with their own independent configuration, storage directory, and X.509 extension handling. * Multiple Subject Name (X.509 DN field) formatting options are supported. For VPNs, this means a cleaner commonName only setup can be used. * A single backend is used across all supported platforms, ensuring that no platform is 'left out' of the rich features. Unix-alikes (BSD, Linux, etc) and Windows are all supported. * Easy-RSA's X.509 support includes CRL, CDP, keyUsage/eKu attributes, and additional features. The included support can be changed or extended as an advanced feature. * Interactive and automated (batch) modes of operation * Flexible configuration: features can be enabled through command-line options, environment variables, a config file, or a combination of these. * Built-in defaults allow Easy-RSA to be used without first editing a config file. Obtaining and Using Easy-RSA ---------------------------- #### Download and extraction (installation) Easy-RSA's main program is a script, supported by a couple of config files. As such, there is no formal "installation" required. Preparing to use Easy-RSA is as simple as downloading the compressed package (.tar.gz for Linux/Unix or .zip for Windows) and extract it to a location of your choosing. There is no compiling or OS-dependent setup required. You should install and run Easy-RSA as a non-root (non-Administrator) account as root access is not required. #### Running Easy-RSA Invoking Easy-RSA is done through your preferred shell. Under Windows, you will use the `EasyRSA Start.bat` program to provide a POSIX-shell environment suitable for using Easy-RSA. The basic format for running commands is: ./easyrsa command [ cmd-opts ] where `command` is the name of a command to run, and `cmd-opts` are any options to supply to the command. Some commands have mandatory or optional cmd-opts. Note the leading `./` component of the command: this is required in Unix-like environments and may be a new concept to some Windows users. General usage and command help can be shown with: ./easyrsa help [ command ] When run without any command, general usage and a list of available commands are shown; when a command is supplied, detailed help output for that command is shown. Configuring Easy-RSA -------------------- Easy-RSA 3 no longer needs any configuration file prior to operation, unlike earlier versions. However, the `vars.example` file contains many commented options that can be used to control non-default behavior as required. Reading this file will provide an idea of the basic configuration available. Note that a vars file must be named just `vars` (without an extension) to actively use it. Additionally, some options can be defined at runtime with options on the command-line. A full list can be shown with: ./easyrsa help options Any of these options can appear before the command as required as shown below: ./easyrsa [options] command [ cmd-opts ] For experts, additional configuration with env-vars and custom X.509 extensions is possible. Consult the [EasyRSA-Advanced](EasyRSA-Advanced.md) documentation for details. Getting Started: The Basics --------------------------- Some of the terms used here will be common to those familiar with how PKI works. Instead of describing PKI basics, please consult the document [Intro-To-PKI](Intro-To-PKI.md) if you need a more basic description of how a PKI works. #### Creating an Easy-RSA PKI In order to do something useful, Easy-RSA needs to first initialize a directory for the PKI. Multiple PKIs can be managed with a single installation of Easy-RSA, but the default directory is called simply "pki" unless otherwise specified. To create or clear out (re-initialize) a new PKI, use the command: ./easyrsa init-pki which will create a new, blank PKI structure ready to be used. Once created, this PKI can be used to make a new CA or generate keypairs. #### The PKI Directory Structure An Easy-RSA PKI contains the following directory structure: * `private/` - dir with private keys generated on this host * `reqs/` - dir with locally generated certificate requests (for a CA imported requests are stored here) In a clean PKI no files exist yet, just the bare directories. Commands called later will create the necessary files depending on the operation. When building a CA, a number of new files are created by a combination of Easy-RSA and (indirectly) openssl. The important CA files are: * `ca.crt` - This is the CA certificate * `index.txt` - This is the "master database" of all issued certs * `serial` - Stores the next serial number (serial numbers increment) * `private/ca.key` - This is the CA private key (security-critical) * `certs_by_serial/` - dir with all CA-signed certs by serial number * `issued/` - dir with issued certs by commonName #### After Creating a PKI Once you have created a PKI, the next useful step will be to either create a CA, or generate keypairs for a system that needs them. Continue with the relevant section below. Using Easy-RSA as a CA ---------------------- #### Building the CA In order to sign requests to produce certificates, you need a CA. To create a new CA in the PKI you have created, run: ./easyrsa build-ca Be sure to use a strong passphrase to protect the CA private key. Note that you must supply this passphrase in the future when performing signing operations with your CA, so be sure to remember it. During the creation process, you will also select a name for the CA called the Common Name (CN.) This name is purely for display purposes and can be set as you like. #### Importing requests to the CA Once a CA is built, the PKI is intended to be used to import requests from external systems that are requesting a signed certificate from this CA. In order to sign the request, it must first be imported so Easy-RSA knows about it. This request file must be a standard CSR in PKCS#10 format. Regardless of the file name to import, Easy-RSA uses a "short name" defined during import to refer to this request. Importing works like this: ./easyrsa import-req /path/to/request.req nameOfRequest The nameOfRequest should normally refer to the system or person making the request. #### Signing a request Once Easy-RSA has imported a request, it can be reviewed and signed: ./easyrsa sign-req nameOfRequest Every certificate needs a `type` which controls what extensions the certificate gets. Easy-RSA ships with 4 possible "types": * `client` - A TLS client, suitable for a VPN user or web browser (web client) * `server` - A TLS server, suitable for a VPN or web server * `ca` - A intermediate CA, used when chaining multiple CAs together * `serverClient` - A TLS server and TLS client Additional types of certs may be defined by local sites as needed; see the advanced documentation for details. #### Revoking and publishing Certificate Revocation Lists (CRLs) If an issue certificate needs to be revoked, this can be done as follows: ./easyrsa revoke nameOfRequest To generate a CRL suitable for publishing to systems that use it, run: ./easyrsa gen-crl Note that this will need to be published or sent to systems that rely on an up-to-date CRL as the certificate is still valid otherwise. Using Easy-RSA to generate keypairs & requests ---------------------------------------------- Easy-RSA can generate a keypair and certificate request in PKCS#10 format. This request is what a CA needs in order to generate and return a signed certificate. Ideally you should never generate entity keypairs for a client or server in a PKI you are using for your CA. It is best to separate this process and generate keypairs only on the systems you plan to use them. Easy-RSA can generate a keypair and request with the following command: ./easyrsa gen-req nameOfRequest You will then be given a chance to modify the Subject details of your request. Easy-RSA uses the short name supplied on the command-line by default, though you are free to change it if necessary. After providing a passphrase and Subject details, the keypair and request files will be shown. In order to obtain a signed certificate, the request file must be sent to the CA for signing; this step is obviously not required if a single PKI is used as both the CA and keypair/request generation as the generated request is already "imported." EasyRSA-3.1.7/doc/EasyRSA-Contributing.md000664 000765 000024 00000004430 14512342147 020436 0ustar00ecriststaff000000 000000 Easy-RSA 3 Github Contributions Documentation ============================================= This document explains how to contribute to Easy-RSA 3. Please follow these simple steps and make contributing easier. Intended audience: Everyone. Contributing Guide ------------------ - **Do not** edit Easy-RSA `master` branch. - **Do not** edit Easy-RSA `master` branch. Pull Requests submitted from `master` branch may be be squashed or rejected. ### Create a new branch: - Select a suitable name for the new branch. eg: `doc-contrib-typo` ``` git checkout -b doc-contrib-typo ``` - Make changes to the new branch. Please use tabs to indent the code but only use tabs at the beginning of the line. - Review the changes: ``` git diff ``` - Stage the changes: ``` git add -A ``` - Show the extent of the changes: ``` git status -v ``` - Commit the changes: ``` git commit -sS ``` Please write a detailed commit message. github `help` has details of creating a private key. Using github `no-reply` email address is suitable for the `Signed-off-by:` line. - Push the changes: ``` git push origin doc-contrib-typo ``` - Share the changes: ``` Raise a Pull Request on github. ``` Keeping your fork syncronised ----------------------------- - Configure the `upstream` remote for your fork: ``` git remote add upstream https://github.com/OpenVPN/easy-rsa.git ``` - Verify the remote sources: ``` git remote -v ``` Remote `origin` will have **your** repository: ``` origin https://github.com/TinCanTech/easy-rsa.git (fetch) origin https://github.com/TinCanTech/easy-rsa.git (push) ``` Remote `upstream` will be `Openvpn/easy-rsa`: ``` upstream https://github.com/Openvpn/easy-rsa.git (fetch) upstream https://github.com/Openvpn/easy-rsa.git (push) ``` ### Syncronising your fork: - Select `master` branch: ``` git checkout master ``` - Fetch changes in `upstream`: ``` git fetch upstream ``` - Merge changes in `upstream`: ``` git merge upstream/master ``` - Update your fork on github: ``` git push ``` Your fork is now syncronised. EasyRSA-3.1.7/doc/Hacking.md000664 000765 000024 00000013403 14512342147 016066 0ustar00ecriststaff000000 000000 Easy-RSA 3 Hacking Guide === This document is aimed at programmers looking to improve on the existing codebase. Compatibility --- The `easyrsa` code is written in POSIX shell (and any cases where it is not is considered a bug to be fixed.) The only exceptions are the `local` keyword and the construct `export FOO=baz`, both well-supported. As such, modifications to the code should also be POSIX; platform-specific code should be placed under the `distro/` dir and listed by target platform. Coding conventions --- While there aren't strict syntax standards associated with the project, please follow the existing format and flow when possible; however, specific exceptions can be made if there is a significant reason or benefit. Do try to: * Keep variables locally-scoped when possible * Comment sections of code for readability * Use the conventions for prefixes on global variables * Set editors for tab stops of 8 spaces * Use tabs for code indents; use aligned spaces for console text Keeping code, docs, and examples in sync --- Changes that adjust, add, or remove features should have relevant docs, help output, and examples updated at the same time. Release versioning --- A point-release bump (eg: 3.0 to 3.1) is required when the frontend interface changes in a non-backwards compatible way. Always assume someone has an automated process that relies on the current functionality for official (non-beta, non-rc) releases. A possible exception exists for bugfixes that do break backwards-compatibility; caution is to be used in such cases. The addition of a new command may or may not require a point-release depending on the significance of the feature; the same holds true for additional optional arguments to commands. Project layout --- The project's files are structured as follows: * `easyrsa3/` is the primary project code. On Linux/Unix-alikes, all the core code and supporting files are stored here. * `Licensing/` is for license docs. * `build/` is for build information and scripts. * `contrib/` is for externally-contributed files, such as useful external scripts or interfaces for other systems/languages. * `distro/` is for distro-specific supporting files, such as the Windows frontend wrappers. Code components that are not platform-neutral should go here. * `doc/` is for documentation. Much of this is in Markdown format which can be easily converted to HTML for easy viewing under Windows. * `release-keys/` list current and former KeyIDs used to sign release packages (not necessarily git tags) available for download. * The top-level dir includes files for basic project info and reference appropriate locations for more detail. As a brief note, it is actually possible to take just the easyrsa3/ dir and end up with a functional project; the remaining structure includes docs, build prep, distro-specific wrappers, and contributed files. Git conventions --- As of Easy-RSA 3, the following git conventions should be used. These are mostly useful for people with repo access in order to keep a standard meaning to commit messages and merge actions. ### Signed-off-by: and related commit message lines Committers with push access should ensure a `Signed-off-by:` line exists at the end of the commit message with their name on it. This indicates that the committer has reviewed the changes to the commit in question and approve of the feature and code in question. It also helps verify the code came from an acceptable source that won't cause issues with the license. This can be automatically added by git using `git commit -s`. Additional references can be included as well. If multiple people reviewed the change, the committer may add their names in additional `Signed-off-by:` lines; do get permission from that person before using their name, however ;) The following references may be useful as well: * `Signed-off-by:` -- discussed above, indicates review of the commit * `Author:` -- references an author of a particular feature, in full or significant part * `Changes-by:` -- indicates the listed party contributed changes or modifications to a feature * `Acked-by:` -- indicates review of the feature, code, and/or functional correctness ### Merging from external sources (forks, patches, etc) Contributions can come in many forms: GitHub "pull requests" from cloned repos, references to external repos, patches to the ML, or others. Those won't necessary have `Signed-off-by:` lines or may contain less info in the commit message than is desirable to explain the changes. The committing author to this project should make a merge-commit in this case with the appropriate details provided there. If additional code changes are necessary, this can be done on a local branch prior to merging back into the mainline branch. This merge-commit should list involved contributors with `Author:` or similar lines as required. The individual commits involved in a merge also retain the original committer; regardless, the merge-commit message should give a clear indication of what the entire set of commits does as a whole. ### Tagging Tags should follow the convention: vM.m.p where `M` is the major version, `m` is the minor "point-release" version, and `p` is the patch-level. Suffixes of `-rc#`, `-beta#`, etc can be added for pre-release versions as required. Currently tags are taken from the mainline development branch in question. The ChangeLog should thus be updated prior to tagging. Tags should also be annotated with an appropriate commit message and signed-off. This can be done as shown below (don't use `-s` unless you intend to use GPG with git.) git tag -a v1.2.3 Corresponding release downloads can be uploaded to release distribution points as required. EasyRSA-3.1.7/doc/EasyRSA-Renew-and-Revoke.md000664 000765 000024 00000007676 14512342147 021057 0ustar00ecriststaff000000 000000 Easy-RSA 3 Certificate Renewal and Revocation Documentation =========================================================== This document explains how the **differing versions** of Easy-RSA 3 work with Renewal and Revocation of Certificates and Private keys. Thanks to _good luck_, _hard work_ and _co-operation_, these version dependent differences have been _smoothed-over_. Since version `3.1.1`, Easy-RSA has the tools required to renew and/or revoke all verified and Valid certifiicates. **UPDATE**: The changes noted for Easy-RSA version 3.1.2 have all been included with Easy-RSA version 3.1.1 - See https://github.com/OpenVPN/easy-rsa/pull/688 Command Details: `renew` ------------------------ easyrsa renew file-name-base [ cmd-opts ] `renew` is **only** available since Easy-RSA version `3.0.6` #### `renew` has three different versions: * `renew` **Version 1**: Easy-RSA version `3.0.6`, `3.0.7` and `3.0.8`. - Both certificate and private key are rebuilt. - Once a certificate has been renewed it **cannot** be revoked. * `renew` **Version 2**: Easy-RSA version `3.0.9` and `3.1.0`. - Both certificate and private key are rebuilt. - Once a certificate has been renewed it **can** be revoked. - Use command: `revoke-renewed file-name-base [ reason ]` * `renew` **Version 3**: Easy-RSA version `3.1.1+`. - Only certificate is renewed. - The original `renew` command has been renamed to `rebuild`, which rebuilds both certificate and private key. Resolving issues with `renew` version 1 --------------------------------------- #### Upgrade Easy-RSA to version `3.1.1+` is required. `renew` version 1 **rebuilds** the certificate and private key. Once a certificate has been renewed by version 1, the files are saved in the `renewed/` storage area by `serialNumber`. These files must be recovered by using command: easyrsa rewind-renew serialNumber Command `rewind-renew` is available since Easy-RSA version `3.1.1` Once `rewind-renew` has recovered the files, the certificate can be revoked: easyrsa revoke-renewed file-name-base [ reason ] Using `renew` version 2 ----------------------- #### Upgrade Easy-RSA to version `3.1.1+` is required. `renew` version 2 **rebuilds** the certificate and private key. Renewed certificate can be revoked: easyrsa revoke-renewed file-name-base [ reason ] Using `renew` version 3 ----------------------- #### Upgrade Easy-RSA to version `3.1.1+` is required. `renew` version 3 **renews** the certificate only. Renewed certificate can be revoked: easyrsa revoke-renewed file-name-base [ reason ] This is the preferred method to renew a certificate because the original private key is still valid. `renew` version 3 is **only** available since Easy-RSA version `3.1.1+`. Easy-RSA Reporting tools for certificate status ----------------------------------------------- Easy-RSA version `3.1.x`, also has the following tools to keep track of certificate staus: easyrsa [ --days=# ] show-expire [ file-name-base ] `show-expire` shows all certificates which will expire in given `--days`. easyrsa show-renew [ file-name-base ] `show-renew` shows all certificates which have been renewed, where the old certificate has not been revoked. easyrsa show-revoke [ file-name-base ] `show-revoke` shows all certificates which have been revoked. Reason codes available for revoke commands ------------------------------------------ The follow is an exhaustive list of available `reason` codes: - `unspecified` - `keyCompromise` - `CACompromise` - `affiliationChanged` - `superseded` - `cessationOfOperation` - `certificateHold` `reason` must be one of these codes, otherwise not be used. About command `rebuild` ----------------------- If `rebuild` is used then the output directory of old certificate, key and request is also the `renewed` directory. Use **`revoke-renewed`** to revoke an old certificate/key pair, which has been _rebuilt_ by command `rebuild`. EasyRSA-3.1.7/doc/EasyRSA-Advanced.md000664 000765 000024 00000015166 14512342147 017504 0ustar00ecriststaff000000 000000 Easy-RSA Advanced Reference ============================= This is a technical reference for advanced users familiar with PKI processes. If you need a more detailed description, see the `EasyRSA-Readme` or `Intro-To-PKI` docs instead. Configuration Reference ----------------------- #### Configuration Sources There are 3 possible ways to perform external configuration of Easy-RSA, selected in the following order where the first defined result wins: 1. Command-line option 2. Environmental variable 3. 'vars' file, if one is present (see `vars Autodetection` below) 4. Built-in default Note that not every possible config option can be set everywhere, although any env-var can be added to the 'vars' file even if it's not shown by default. #### vars Autodetection A 'vars' file is a file named simply `vars` (without an extension) that Easy-RSA will source for configuration. This file is specifically designed *not* to replace variables that have been set with a higher-priority method such as CLI opts or env-vars. The following locations are checked, in this order, for a vars file. Only the first one found is used: 1. The file referenced by the `--vars` CLI option 2. The file referenced by the env-var named `EASYRSA_VARS_FILE` 3. The directory referenced by the `--pki` CLI option (Recommended) 4. The directory referenced by the `EASYRSA_PKI` env-var 5. The directory referenced by the `EASYRSA` env-var 6. The default PKI directory at `$PWD/pki` (See note below) 7. The default working directory at `$PWD` Defining the env-var `EASYRSA_NO_VARS` will override the sourcing of the vars file in all cases, including defining it subsequently as a global option. Note: If the vars file `$PWD/pki/vars` is sourced then it is forbidden from setting/changing the current PKI, as defined by `EASYRSA_PKI` env-var. #### Use of `--pki` verses `--vars` It is recommended to use option `--pki=DIR` to define your PKI at runtime. This method will always auto-load the `vars` file found in defined PKI. In a multi-PKI installation, use of `--vars` can potentially lead to a vars file that is configured to set a PKI which cannot be verified as the expected PKI. Use of `--vars` is not recommended. #### OpenSSL Config Easy-RSA is tightly coupled to the OpenSSL config file (.cnf) for the flexibility the script provides. It is required that this file be available, yet it is possible to use a different OpenSSL config file for a particular PKI, or even change it for a particular invocation. The OpenSSL config file is searched for in the following order: 1. The env-var `EASYRSA_SSL_CONF` 2. The 'vars' file (see `vars Autodetection` above) 3. The `EASYRSA_PKI` directory with a filename of `openssl-easyrsa.cnf` 4. The `EASYRSA` directory with a filename of `openssl-easyrsa.cnf` Advanced extension handling --------------------------- Normally the cert extensions are selected by the cert type given on the CLI during signing; this causes the matching file in the x509-types subdirectory to be processed for OpenSSL extensions to add. This can be overridden in a particular PKI by placing another x509-types dir inside the `EASYRSA_PKI` dir which will be used instead. The file named `COMMON` in the x509-types dir is appended to every cert type; this is designed for CDP usage, but can be used for any extension that should apply to every signed cert. Additionally, the contents of the env-var `EASYRSA_EXTRA_EXTS` is appended with its raw text added to the OpenSSL extensions. The contents are appended as-is to the cert extensions; invalid OpenSSL configs will usually result in failure. Environmental Variables Reference --------------------------------- A list of env-vars, any matching global option (CLI) to set/override it, and a short description is shown below: * `EASYRSA` - should point to the Easy-RSA top-level dir, where the easyrsa script is located. * `EASYRSA_OPENSSL` - command to invoke openssl * `EASYRSA_SSL_CONF` - the openssl config file to use * `EASYRSA_PKI` (CLI: `--pki-dir`) - dir to use to hold all PKI-specific files, defaults to `$PWD/pki`. * `EASYRSA_VARS_FILE` (CLI: `--vars`) - Set the `vars` file to use * `EASYRSA_DN` (CLI: `--dn-mode`) - set to the string `cn_only` or `org` to alter the fields to include in the req DN * `EASYRSA_REQ_COUNTRY` (CLI: `--req-c`) - set the DN country with org mode * `EASYRSA_REQ_PROVINCE` (CLI: `--req-st`) - set the DN state/province with org mode * `EASYRSA_REQ_CITY` (CLI: `--req-city`) - set the DN city/locality with org mode * `EASYRSA_REQ_ORG` (CLI: `--req-org`) - set the DN organization with org mode * `EASYRSA_REQ_EMAIL` (CLI: `--req-email`) - set the DN email with org mode * `EASYRSA_REQ_OU` (CLI: `--req-ou`) - set the DN organizational unit with org mode * `EASYRSA_REQ_SERIAL` (CLI: `--req-serial`) - set the DN serialNumber with org mode (OID 2.5.4.5) * `EASYRSA_KEY_SIZE` (CLI: `--keysize`) - set the key size in bits to generate * `EASYRSA_ALGO` (CLI: `--use-algo`) - set the crypto alg to use: rsa, ec or ed * `EASYRSA_CURVE` (CLI: `--curve`) - define the named EC curve to use * `EASYRSA_CA_EXPIRE` (CLI: `--days`) - set the CA expiration time in days * `EASYRSA_CERT_EXPIRE` (CLI: `--days`) - set the issued cert expiration time in days * `EASYRSA_CRL_DAYS` (CLI: `--days`) - set the CRL 'next publish' time in days * `EASYRSA_NS_SUPPORT` (CLI: `--ns-cert`) - string 'yes' or 'no' fields to include the **deprecated** Netscape extensions * `EASYRSA_NS_COMMENT` (CLI: `--ns-comment`) - string comment to include when using the **deprecated** Netscape extensions extensions * `EASYRSA_REQ_CN` (CLI: `--req-cn`) - default CN, can only be used in BATCH mode * `EASYRSA_DIGEST` (CLI: `--digest`) - set a hash digest to use for req/cert signing * `EASYRSA_BATCH` (CLI: `--batch`) - enable batch (no-prompt) mode; set env-var to non-zero string to enable (CLI takes no options) * `EASYRSA_PASSIN` (CLI: `--passin`) - allows to specify a source for password using any openssl password options like pass:1234 or env:var * `EASYRSA_PASSOUT` (CLI: `--passout`) - allows to specify a source for password using any openssl password options like pass:1234 or env:var * `EASYRSA_NO_PASS` (CLI: `--nopass`) - disable use of passwords * `EASYRSA_UMASK` - safe umask to use for file creation. Defaults to `077` * `EASYRSA_NO_UMASK` - disable safe umask. Files will be created using the system's default * `EASYRSA_TEMP_DIR` (CLI: `--tmp-dir`) - a temp directory to use for temporary files **NOTE:** the global options must be provided before the commands. EasyRSA-3.1.7/doc/EasyRSA-Upgrade-Notes.md000664 000765 000024 00000005222 14512342147 020444 0ustar00ecriststaff000000 000000 Upgrading to Easy-RSA 3 from earlier versions ========= People upgrading to Easy-RSA 3 from a 2.x version should note some important changes starting with version 3. For a better overview of version 3 in general, see the Readme in the doc/ directory. Easy-RSA 3 comes with an automated upgrade utility to convert an existing 2.x PKI to version 3. For details, see [this article on the OpenVPN wiki](https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade). List of important changes ---- * nsCertType extensions are no longer included by default. Use of such "Netscape" attributes have been deprecated upstream and their use is discouraged. Configure `EASYRSA_NS_SUPPORT` in vars if you want to enable this legacy behavior. Notably, this is important for OpenVPN deployments relying on the `--ns-cert-type` directive. Either have OpenVPN use the preferred `--remote-cert-tls` option, or enable legacy NS extensions. * The default request Subject (or DN, Distinguished Name) includes just the commonName. This is more suitable for VPNs and environments that don't wish to include info about the Country/State/City/Org/OU in certs. Configure `EASYRSA_DN` in vars if you want to enable the legacy behavior. * The 3.0 release lacks PKCS#11 (smartcard/token) support. This is anticipated to be supported in a future point-release to target each platform's need. * The -utf8 option has been added for all supported commands. This should be backwards compatible with ASCII strings. * The default private key encryption has been changed from 3des to aes256. Some new concepts ---- Easy-RSA 3 has some new concepts compared to the prior v2 series. ### Request-Import-Sign workflow v3 is now designed to support keypairs generated on the target system where they will be used, thus improving security as no keys need to be transferred between hosts. The old workflow of generating everything in a single PKI is still supported as well. The recommended workflow when using Easy-RSA as a CA is to import requests, sign them, and return the issued & CA certs. Each requesting system can use Easy-RSA without a CA to generate keypairs & requests. ### "Org"-style DN flexibility When using Easy-RSA in the "org" DN mode, it is no longer required to match some of the field values. This improves flexibility, and enables easier remote generation as the requester doesn't need to know the CA's values in advance. Previously in v2, the Country, State, and Org values all had to match or a request couldn't be signed. If you want the old behavior you can change the OpenSSL config to require it or simply look over the DN at signing time. EasyRSA-3.1.7/x509-types/ca000664 000765 000024 00000000651 14512342147 015611 0ustar00ecriststaff000000 000000 # X509 extensions for a ca # Note that basicConstraints will be overridden by Easy-RSA when defining a # CA_PATH_LEN for CA path length limits. You could also do this here # manually as in the following example in place of the existing line: # # basicConstraints = CA:TRUE, pathlen:1 basicConstraints = CA:TRUE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always keyUsage = cRLSign, keyCertSign EasyRSA-3.1.7/x509-types/server000664 000765 000024 00000000317 14512342147 016533 0ustar00ecriststaff000000 000000 # X509 extensions for a server basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always extendedKeyUsage = serverAuth keyUsage = digitalSignature,keyEncipherment EasyRSA-3.1.7/x509-types/COMMON000664 000765 000024 00000000755 14512342147 016223 0ustar00ecriststaff000000 000000 # X509 extensions added to every signed cert # This file is included for every cert signed, and by default does nothing. # It could be used to add values every cert should have, such as a CDP as # demonstrated in the following example: #crlDistributionPoints = URI:http://example.net/pki/my_ca.crl # The authority information access extension gives details about how to access # certain information relating to the CA. #authorityInfoAccess = caIssuers;URI:http://example.net/pki/my_ca.crt EasyRSA-3.1.7/x509-types/kdc000664 000765 000024 00000001225 14512342147 015765 0ustar00ecriststaff000000 000000 # X509 extensions for a KDC server certificate basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always extendedKeyUsage = 1.3.6.1.5.2.3.5 keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement issuerAltName = issuer:copy subjectAltName = otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name [kdc_princ_name] realm = EXP:0,GeneralString:${ENV::EASYRSA_KDC_REALM} principal_name = EXP:1,SEQUENCE:kdc_principal_seq [kdc_principal_seq] name_type = EXP:0,INTEGER:1 name_string = EXP:1,SEQUENCE:kdc_principals [kdc_principals] princ1 = GeneralString:krbtgt princ2 = GeneralString:${ENV::EASYRSA_KDC_REALM} EasyRSA-3.1.7/x509-types/code-signing000664 000765 000024 00000000300 14512342147 017563 0ustar00ecriststaff000000 000000 # X509 extensions for a client basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always extendedKeyUsage = codeSigning keyUsage = digitalSignature EasyRSA-3.1.7/x509-types/client000664 000765 000024 00000000277 14512342147 016510 0ustar00ecriststaff000000 000000 # X509 extensions for a client basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always extendedKeyUsage = clientAuth keyUsage = digitalSignature EasyRSA-3.1.7/x509-types/email000664 000765 000024 00000000340 14512342147 016310 0ustar00ecriststaff000000 000000 # X509 extensions for email basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always extendedKeyUsage = emailProtection keyUsage = digitalSignature,keyEncipherment,nonRepudiation EasyRSA-3.1.7/x509-types/serverClient000664 000765 000024 00000000341 14512342147 017667 0ustar00ecriststaff000000 000000 # X509 extensions for a client/server basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always extendedKeyUsage = serverAuth,clientAuth keyUsage = digitalSignature,keyEncipherment