├── .github ├── FUNDING.yml ├── README.md └── workflows │ └── blank.yml ├── .gitignore ├── LICENSE ├── dev ├── easytls-caution.svg ├── easytls-code-archive.txt ├── easytls-export-libs.sh ├── easytls-metadata.lib ├── easytls-op-test.bat ├── easytls-op-test.sh ├── easytls-openvpn.diff ├── easytls-shellcheck.sh ├── easytls-tctip.lib ├── easytls-unit-tests.sh ├── et-tdir1.tar ├── et-tdir2.tar └── et-tdir3.tar ├── doc ├── easytls-change.log ├── easytls-details.txt └── easytls-howto-ii.md ├── easytls ├── easytls-client-connect.sh ├── easytls-client-disconnect.sh ├── easytls-conntrac.lib ├── easytls-cryptv2-verify.sh └── examples ├── easytls-client-connect.vars-example ├── easytls-client-disconnect.vars-example ├── easytls-cryptv2-verify.vars-example └── easytls-script.conf-example /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | #github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | #patreon: # Replace with a single Patreon username 5 | #open_collective: # Replace with a single Open Collective username 6 | #ko_fi: # Replace with a single Ko-fi username 7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | #liberapay: # Replace with a single Liberapay username 10 | #issuehunt: # Replace with a single IssueHunt username 11 | #otechie: # Replace with a single Otechie username 12 | #custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | custom: ["https://paypal.me/richardTbonhomme"] 14 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/TinCanTech/easy-tls/actions/workflows/blank.yml/badge.svg)](https://github.com/TinCanTech/easy-tls/actions/workflows/blank.yml) 2 | # Easy-TLS 3 | 4 | From that list above, the only file which you need is: [**`easytls`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls) 5 | 6 | ## Standard Features 7 | Easy-TLS is an Easy-RSA extension utility to help manage: 8 | + Easy-RSA based x509 security credentials 9 | + OpenVPN specific TLS keys 10 | + Verified **`Inline`** files for use with OpenVPN 11 | + Concise OpenVPN TLS-Crypt-V2 Client Key Metadata definition 12 | + X509 Certificate **and matched** Easy-TLS Inline-file Expiry management tools 13 | + Substantial **Inter-active Menus** 14 | 15 | ## Additional Features 16 | Easy-TLS also supports No-CA mode, which does not require an Easy-RSA CA: 17 | + Use Easy-TLS to build **self-signed** X509 Certificates and keys. 18 | 19 | ### Installation 20 | Download: [**`easytls`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls) to your `easyrsa3` working directory. 21 | 22 | For full support, you will also need these scripts for use by your OpenVPN Server: 23 | + [**`easytls-cryptv2-verify.sh (1)`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls-cryptv2-verify.sh) - **Can be used stand-alone**
24 | Used by Openvpn-Server to enforce TLS-Crypt-V2 `metadata` access policy rules.
25 | 26 | + [**`easytls-client-connect.sh (2)`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls-client-connect.sh) - **Requires script `(1)(3)`**
27 | Used by Openvpn-Server to enforce `TLS-Key-type` and `address-filter` access policy rules.
28 | 29 | + [**`easytls-client-disconnect.sh (3)`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls-client-disconnect.sh) - **Requires script `(1)(2)`**
30 | This Disconnect script is **required by** the Connect script. 31 | 32 | + Optional - [**`easytls-conntrac.lib`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls-conntrac.lib) - **Requires script `(1)(2)(3)`**
33 | Connection tracking plug-in, required for optional connection tracking. 34 | 35 | ### Environment 36 | **`easytls`** is intended to work **everywhere** that **`openvpn`** and **`easyrsa`** work. 37 | 38 | ### Requirements 39 | + Easy-RSA Version 3.0.6+ 40 | + OpenVPN Version 2.5.0+ 41 | 42 | ### Support 43 | Please use the issues section here on github.
44 | For live support you can use IRC channel: **libera.chat/#easytls**
45 | Wiki: https://github.com/TinCanTech/easy-tls/wiki
46 | Howto: https://github.com/TinCanTech/easy-tls/blob/master/EasyTLS-Howto-ii.md
47 | 48 | ## Acknowledgements 49 | Easy-TLS is *written in the style of* and *borrows heavily from* Easy-RSA
50 | See: https://github.com/OpenVPN/easy-rsa
51 | **Note:**
52 | This is intended to facilitate maximum compatibility with Easy-RSA while extending functionality
53 | to include direct support for OpenVPN specific TLS keys and Inline credentials.
54 | 55 | ### Easy-TLS is inspired by **syzzer**
56 | See: https://github.com/OpenVPN/openvpn/blob/master/doc/tls-crypt-v2.txt
57 | 58 | I hope that you find Easy-TLS to be a useful tool. 59 | 60 | -------------------------------------------------------------------------------- /.github/workflows/blank.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | push: 9 | branches: [ master ] 10 | pull_request: 11 | branches: [ master ] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | # This workflow contains a single job called "build" 19 | xtest: 20 | # The type of runner that the job will run on 21 | runs-on: ubuntu-latest 22 | 23 | env: 24 | EASYTLS_REMOTE_CI: 1 25 | TERM: xterm-256color 26 | 27 | # Steps represent a sequence of tasks that will be executed as part of the job 28 | steps: 29 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 30 | - uses: actions/checkout@v3 31 | 32 | # Runs a single command using the runners shell 33 | - name: Run a one-line script 34 | run: sh dev/easytls-op-test.sh 35 | 36 | # Runs a set of commands using the runners shell 37 | # - name: Run a multi-line script 38 | # run: | 39 | # echo Add other actions to build, 40 | # echo test, and deploy your project. 41 | # This workflow contains a single job called "build" 42 | 43 | wtest: 44 | # The type of runner that the job will run on 45 | runs-on: windows-latest 46 | 47 | env: 48 | EASYTLS_REMOTE_CI: 1 49 | TERM: xterm-256color 50 | 51 | # Steps represent a sequence of tasks that will be executed as part of the job 52 | steps: 53 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 54 | - uses: actions/checkout@v3 55 | 56 | # Runs a single command using the runners shell 57 | - name: Run a one-line script 58 | run: cmd /c dev\easytls-op-test.bat 59 | 60 | # Runs a set of commands using the runners shell 61 | # - name: Run a multi-line script 62 | # run: | 63 | # echo Add other actions to build, 64 | # echo test, and deploy your project. 65 | 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /easytls-script.conf 2 | easytls-*.vars 3 | ia-*.* 4 | et-tdir*/* 5 | noca/* 6 | easyrsa 7 | vars 8 | vars.example 9 | openssl-easyrsa.cnf 10 | safessl-easyrsa.cnf 11 | x509-types/* 12 | unit-test-tmp/* 13 | debug/* 14 | test/* 15 | pki/* 16 | 0 0/* 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /dev/easytls-caution.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /dev/easytls-code-archive.txt: -------------------------------------------------------------------------------- 1 | Archive old code 2 | ================ 3 | 4 | : << 'DISABLED_INLINE_RENEW' 5 | 6 | [ $# -ge 1 ] || die "Required option(s): " 7 | 8 | name="$1" 9 | shift 10 | 11 | cmd_opts="" 12 | while [ -n "$1" ]; do 13 | case "$1" in 14 | 0|1) key_direction="$1" ;; 15 | add-dh) cmd_opts="$cmd_opts add-dh" ;; 16 | no-key) cmd_opts="$cmd_opts no-key" ;; 17 | *) warn "Ignoring unknown command option: '$1'" ;; 18 | esac 19 | shift 20 | done 21 | 22 | inline_file="$EASYTLS_PKI/$name.inline" 23 | crt_file="$EASYRSA_PKI/issued/$name.crt" 24 | 25 | [ -f "$inline_file" ] || die "inline_renew: Missing: $inline_file" 26 | [ -f "$crt_file" ] || die "inline_renew: Missing: $crt_file" 27 | # This is very borked 28 | #x509_cert_serial 29 | die "inline_renew is borked" 30 | 31 | # Collect the attributes of .inline file 32 | inline_is_base="$("$EASYTLS_GREP" -c '^# EasyTLS - File name base:.*$' "$inline_file")" 33 | inline_is_tlsauth="$("$EASYTLS_GREP" -c '^$' "$inline_file")" 34 | inline_is_tlscrypt="$("$EASYTLS_GREP" -c '^$' "$inline_file")" 35 | inline_is_tlscryptv2="$("$EASYTLS_GREP" -c '^$' "$inline_file")" 36 | 37 | # Verify .inline is valid 38 | [ $inline_is_base -eq 1 ] || \ 39 | die "File is not valid .inline: $inline_file" 40 | one_type=$((inline_is_tlsauth+inline_is_tlscrypt+inline_is_tlscryptv2)) 41 | [ $one_type -le 1 ] || die "File is not valid .inline: $inline_file" 42 | 43 | # Determine the type of .inline file 44 | inline_type="tls-base" 45 | [ $inline_is_tlsauth -eq 1 ] && inline_type="tls-auth" 46 | [ $inline_is_tlscrypt -eq 1 ] && inline_type="tls-crypt" 47 | [ $inline_is_tlscryptv2 -eq 1 ] && inline_type="tls-crypt-v2" 48 | 49 | # If --key-direction is specified in command line but does not match 50 | # current inline setting then issue a warning 51 | if [ "$inline_type" = "tls-auth" ] && [ $key_direction ] 52 | then 53 | # Determine inline 54 | is_key_dir="$(inline_renew_key_direction)" 55 | case "$is_key_dir" in 56 | 0|1) 57 | # Verify if command line wants to change inline 58 | [ $key_direction -eq $is_key_dir ] || \ 59 | warn "Command line will change inline key-direction" 60 | ;; 61 | *) 62 | # Assume key-direction is missing from inline 63 | warn "TLS-auth key-direction missing" 64 | ;; 65 | esac 66 | fi 67 | 68 | # Auto-detect --key-direction if not specified in command line 69 | # default to current inline file or no_key_direction 70 | if [ "$inline_type" = "tls-auth" ] && [ ! $key_direction ] 71 | then 72 | # Determine inline 73 | is_key_dir="$(inline_renew_key_direction)" 74 | case "$is_key_dir" in 75 | 0|1) key_direction="$is_key_dir" ;; 76 | *) warn "TLS-auth key-direction missing" ;; 77 | esac 78 | fi 79 | 80 | # Confirm renew type 81 | confirm "Renew inline file ? " "yes" \ 82 | "Renew: $inline_file as Type: $inline_type" 83 | 84 | # Make a backup of inline file incase renew fails 85 | [ -f "$inline_file.backup" ] && \ 86 | die "Backup already exists: $inline_file.backup" 87 | "$EASYTLS_CP" "$inline_file" "$inline_file.backup" || \ 88 | die "Unable to create backup: $inline_file.backup" 89 | 90 | # Remove the old .inline file 91 | # .inline HASH is checked prior to removal 92 | silent_remove=1 93 | inline_remove "$name" 94 | 95 | # Disable completion notices from sub processes 96 | #silent_inline=1 97 | 98 | # Build the new .inline file 99 | case "$inline_type" in 100 | tls-base) 101 | inline_base "$name" $cmd_opts || \ 102 | die "Failed to create inline base file" 103 | inline_index_update add 104 | ;; 105 | tls-auth) 106 | inline_tls_auth "$name" "$key_direction" $cmd_opts 107 | ;; 108 | tls-crypt) 109 | inline_tls_crypt_v1 "$name" $cmd_opts 110 | ;; 111 | tls-crypt-v2) 112 | inline_tls_crypt_v2 "$name" $cmd_opts 113 | ;; 114 | *) 115 | die "Unknown error inline_type: $inline_type" 116 | ;; 117 | esac 118 | 119 | # Renew successful, remove the backup 120 | "$EASYTLS_RM" -f "$inline_file.backup" 121 | 122 | notice "Inline $inline_type file renewed: $inline_file" 123 | 124 | DISABLED_INLINE_RENEW 125 | 126 | 127 | 128 | 129 | 130 | # TODO 131 | # TODO WARNING, inline_index_rebuild is a work in progress 132 | # TODO 133 | 134 | : << 'DISABLED_INLINE_INDEX_REBUILD' 135 | 136 | # Do not over write current easytls-inline-index.txt.backup 137 | [ -f "$EASYTLS_INLINE_INDEX.backup" ] && \ 138 | die "Backup file already exists: $EASYTLS_INLINE_INDEX.backup" 139 | 140 | # Do not over write current easytls-inline-index.hash.backup 141 | [ -f "$EASYTLS_INLINE_X_HASH.backup" ] && \ 142 | die "Backup file already exists: $EASYTLS_INLINE_X_HASH.backup" 143 | 144 | # Warn! 145 | confirm "Rebuild inline index file ? " "yes" \ 146 | "WARNING: You are about to rebuild easytls-index.txt" 147 | 148 | # Backup current easytls-inline-index.txt 149 | "$EASYTLS_CP" "$EASYTLS_INLINE_INDEX" "$EASYTLS_INLINE_INDEX.backup" || \ 150 | die "Failed to backup: $EASYTLS_INLINE_INDEX" 151 | 152 | # Backup current easytls-inline-index.hash.backup 153 | "$EASYTLS_CP" "$EASYTLS_INLINE_X_HASH" "$EASYTLS_INLINE_X_HASH.backup" || \ 154 | die "Failed to backup: $EASYTLS_INLINE_X_HASH" 155 | 156 | # Check OpenSSL index.txt 157 | [ -f "$EASYRSA_INDEX" ] || missing_file "$EASYRSA_INDEX" 158 | 159 | # Flag for functions which need to know the index is being rebuilt 160 | index_rebuild=1 161 | 162 | # Get list of inline file names by extracting CN and sub from index 163 | etls_inline_CNsub_name_list="$(inline_index_cn_subname_list)" 164 | 165 | # Create tls dir index file 166 | generate_and_validate_date head_date 167 | head_text="# EastTLS inline-index - Created: $head_date" 168 | "$EASYTLS_PRINTF" '%s\n' "$head_text" > "$EASYTLS_INLINE_INDEX" || \ 169 | inline_index_rebuild_reset "Failed to create inline-index" 170 | 171 | # Create inline-index hash file 172 | inline_index_save_hash || \ 173 | inline_index_rebuild_reset "Failed to create inline-index Hash." 174 | 175 | # Create records from EasyTLS index names 176 | for i in $etls_inline_CNsub_name_list 177 | do 178 | # Reset flag 179 | unset add_inline_record 180 | 181 | # Clear the previous HASH 182 | unset inline_hash 183 | 184 | # THIS CAN GO 185 | # If the name is not a single word then the certificate 186 | # has been renewed in EasyRSA, which means: 187 | # There are two Valid record in OpenSSL index.txt 188 | # with the same CommonName 189 | # Mitigate this disaster here 190 | #name="$("$EASYTLS_PRINTF" "%s" "$i" | "$EASYTLS_AWK" 1 ORS=' ')" 191 | #name="${name%% *}" 192 | 193 | inline_file="$EASYTLS_PKI/$i.inline" 194 | [ -f "$inline_file" ] || \ 195 | inline_index_rebuild_reset "Missing Inline file: $inline_file" 196 | 197 | # Inline serial 198 | x509_cert_serial "${inline_file}" inline_serial || { 199 | error_msg "inline_index_update - x509_cert_serial" 200 | return 1 201 | } 202 | 203 | easytls_verbose "inline_serial: ^$inline_serial^" 204 | [ -z "$inline_serial" ] && \ 205 | inline_index_rebuild_reset "inline_index_rebuild: No inline_serial" 206 | 207 | inline_common_name="" 208 | inline_crt_common_name 209 | easytls_verbose "inline_common_name: ^$inline_common_name^" 210 | [ -z "$inline_common_name" ] && \ 211 | inline_index_rebuild_reset \ 212 | "inline_index_rebuild: No inline_common_name" 213 | 214 | if [ "$i" = "$inline_common_name" ] 215 | then 216 | unset sub_name 217 | unset TLSKEY_SUBNAME 218 | else 219 | # This is ugly and needs to be re-thought 220 | sub_name="${i##"${inline_common_name}-"}" 221 | TLSKEY_SUBNAME="$sub_name" 222 | fi 223 | 224 | name="$inline_common_name" 225 | [ -z "$name" ] && inline_index_rebuild_reset "No name" 226 | easytls_verbose "name: ^$name^" 227 | 228 | # If the x509 cert is missing the inline file still has a copy. 229 | # The cert may have been revoked and this will create an invalid 230 | # record which can be removed with `inline-remove` 231 | crt_file="$EASYRSA_PKI/issued/$name.crt" 232 | [ -f "$crt_file" ] || warn "Missing crt_file: $crt_file" 233 | 234 | # If there is an inline file for this name 235 | # then recreate the inline easytls-index record 236 | # EasyTLS User can remove/create a new inline file 237 | # Note: The extra space .. 238 | [ -f "$inline_file" ] && { 239 | add_inline_record=1 240 | etls_inline_record_list="$etls_inline_record_list $name " 241 | } 242 | 243 | # Add the record 244 | # TODO: Add die here 245 | [ $add_inline_record ] && inline_index_update add 246 | : 247 | done 248 | 249 | # Inform 250 | notice "Inline index file successfully rebuilt: $EASYTLS_INLINE_INDEX" 251 | notice "Use 'easytls status' to confirm." 252 | print 253 | 254 | DISABLED_INLINE_INDEX_REBUILD 255 | 256 | 257 | 258 | # Reset files if index rebuild fails 259 | inline_index_rebuild_reset () 260 | { 261 | : << DISABLED_INLINE_INDEX_REBUILD_RESET 262 | 263 | "$EASYTLS_CP" -f "$EASYTLS_INLINE_INDEX.backup" "$EASYTLS_INLINE_INDEX" 264 | "$EASYTLS_RM" -f "$EASYTLS_INLINE_INDEX.backup" 265 | 266 | "$EASYTLS_CP" -f "$EASYTLS_INLINE_X_HASH.backup" "$EASYTLS_INLINE_X_HASH" 267 | "$EASYTLS_RM" -f "$EASYTLS_INLINE_X_HASH.backup" 268 | 269 | die "Inline index rebuild failed." 270 | 271 | DISABLED_INLINE_INDEX_REBUILD_RESET 272 | 273 | } # => inline_index_rebuild_reset () 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | # easytls-verify.sh - Required for --tls-auth or --tls-crypt clients 282 | #[ $opt_client_connect ] && { 283 | # "$EASYTLS_PRINTF" '%s' 'tls-verify' 284 | # "$EASYTLS_PRINTF" ' %s' "'" 285 | # [ -n "${EASYTLS_FOR_WINDOWS}" ] && \ 286 | # "$EASYTLS_PRINTF" "%s " "$EASYTLS_SH_EXE" 287 | # "$EASYTLS_PRINTF" '%s' "${EASYTLS_VERIFY_V1_SH}" 288 | # "$EASYTLS_PRINTF" ' %s' "-l=${EASYTLS_VERIFY_V1_VARS}" 289 | # [ "$opt_no_ca" ] && "$EASYTLS_PRINTF" ' %s' "${opt_no_ca}" 290 | # "$EASYTLS_PRINTF" ' %s' "-c=${opt_ca_path}" 291 | # [ "$opt_tmp_dir" ] && "$EASYTLS_PRINTF" ' %s' "${opt_tmp_dir}" 292 | # "$EASYTLS_PRINTF" '%s\n\n' "'" 293 | # } 294 | 295 | 296 | 297 | 298 | ############################################################################ 299 | # 300 | # IMPORT Section 301 | # 302 | 303 | # Import pre-existing TLS keys 304 | import_key () 305 | { 306 | # Temporarily disabled 307 | error_msg "'import-key' has been disabled until further notice." 308 | return 1 309 | 310 | [ "$#" -ge 2 ] || \ 311 | die "Required option(s): " 312 | key_type="$1" 313 | 314 | # WARNING: Cannot verify the source is actually a valid key! 315 | key_file="$2" 316 | [ -f "$key_file" ] || die "Cannot find file: $key_file" 317 | 318 | case "$key_type" in 319 | tls-auth) 320 | dest_key="$EASYTLS_PKI/tls-auth.key" 321 | [ -f "$dest_key" ] && die "Key file exists: $dest_key" 322 | "$EASYTLS_CP" "$key_file" "$dest_key" || \ 323 | die "Failed to import file: $key_file" 324 | ;; 325 | tls-crypt) 326 | dest_key="$EASYTLS_PKI/tls-crypt.key" 327 | [ -f "$dest_key" ] && die "Key file exists: $dest_key" 328 | "$EASYTLS_CP" "$key_file" "$dest_key" || \ 329 | die "Failed to import file: $key_file" 330 | ;; 331 | tls-crypt-v2) 332 | # Validate commonName 333 | default_cert_CN="${key_file%.key}" 334 | requested_cert_CN="${3:-$default_cert_CN}" 335 | 336 | cert_file="$EASYRSA_PKI/$requested_cert_CN.crt" 337 | [ -f "$cert_file" ] || die "Cannot find file: $cert_file" 338 | actual_cert_CN="$(easytls_ssl_crt_common_name)" 339 | 340 | if [ "$requested_cert_CN" = "$actual_cert_CN" ] 341 | then 342 | : # CN OK 343 | else 344 | help_note="Requested CN $requested_cert_CN" 345 | die "does not match certificate $actual_cert_CN" 346 | fi 347 | 348 | dest_key="$EASYTLS_PKI/$actual_cert_CN-tls-crypt-v2.key" 349 | [ -f "$dest_key" ] && die "Key file exists: $dest_key" 350 | "$EASYTLS_CP" "$key_file" "$dest_key" || \ 351 | die "Failed to import file: $key_file" 352 | ;; 353 | *) 354 | die "Unknown key type: $key_type" 355 | ;; 356 | esac 357 | 358 | notice "Successfully imported $key_type key from $key_file to $dest_key" 359 | } 360 | 361 | 362 | 363 | 364 | import-key) text="* DISABLED * 365 | import-key 366 | Import a pre-existing TLS key to EasyTLS directory. 367 | 368 | is one of the supported TLS key types: 369 | tls-auth, tls-crypt or tls-crypt-v2. 370 | 371 | Examples (Using default PKI directory): 372 | 373 | Importing TLS-Auth or TLS-Crypt keys renames the key file as shown: 374 | 375 | * 'import-key tls-auth ./ta.key' 376 | Imported key name: ./pki/easytls/tls-auth.key 377 | 378 | * 'import-key tls-crypt ./tc.key' 379 | Imported key name: ./pki/easytls/tls-crypt.key 380 | 381 | TLS-crypt-v2 keys must be named after the commonName of the entity: 382 | (Default is ) 383 | 384 | * 'import-key tls-crypt-v2 ./serv-v2.key server' 385 | Imported key name: ./pki/easytls/server-tls-crypt-v2.key 386 | 387 | * 'import-key tls-crypt-v2 ./cli2-v2.key client02' 388 | Imported key name: ./pki/easytls/client02-tls-crypt-v2.key 389 | 390 | * DISABLED *" ;; 391 | 392 | 393 | 394 | 395 | 396 | # Update disabled-list footer and hash 397 | # TODO: is footer necessary ? 398 | disabled_list_update () 399 | { 400 | die "DISABLE - disabled_list_update" 401 | 402 | # Update time-stamp 403 | update_date="${local_date_ascii}" 404 | 405 | # back up 406 | "${EASYTLS_CP}" "${EASYTLS_DISABLED_LIST}" "${EASYTLS_DISABLED_LIST}.tmp" 407 | 408 | update_text="# Updated: ${update_date} -- ${action}: ${name}" 409 | "${EASYTLS_SED}" -i -e '/^# Updated: .*$/d' "${EASYTLS_DISABLED_LIST}" || { 410 | error_msg "disabled_list_update_and_hash - sed failed" 411 | return 1 412 | } 413 | 414 | # Create temp record file 415 | "${EASYTLS_PRINTF}" '%s\n' "${update_text}" > "${EASYTLS_TEMP_RECORD}" || { 416 | error_msg "disabled_list_update_and_hash - printf failed" 417 | return 1 418 | } 419 | 420 | # Append temp record to disabled-list 421 | "${EASYTLS_CP}" "${EASYTLS_DISABLED_LIST}" "${EASYTLS_TEMP_LIST}" || { 422 | error_msg "disabled_list_update_and_hash - cp failed" 423 | return 1 424 | } 425 | 426 | "${EASYTLS_CAT}" "${EASYTLS_TEMP_LIST}" "${EASYTLS_TEMP_RECORD}" > \ 427 | "${EASYTLS_DISABLED_LIST}" || { 428 | error_msg "disabled_list_update_and_hash - cat failed" 429 | return 1 430 | } 431 | 432 | # Remove temp files 433 | "${EASYTLS_RM}" -f "${EASYTLS_TEMP_LIST}" "${EASYTLS_TEMP_RECORD}" \ 434 | "${EASYTLS_DISABLED_LIST}.tmp" 435 | } # => disabled_list_update () 436 | 437 | 438 | 439 | 440 | 441 | # # Find the pattern 442 | # "${EASYTLS_GREP}" -q "^${cfg_opt}[[:blank:]]=[[:blank:]].*$" \ 443 | # "${EASYTLS_CONFIG_FILE}" || { 444 | # error_msg "config_update - input error: ${cfg_opt}" 445 | # return 1 446 | # } 447 | # 448 | # # backup 449 | # "${EASYTLS_CP}" "${EASYTLS_CONFIG_FILE}" "${EASYTLS_CONFIG_FILE}.tmp" || { 450 | # error_msg "config_update - backup" 451 | # return 1 452 | # } 453 | # 454 | # # Replace the pattern 455 | # [ "${cfg_val}" != "0" ] || unset -v cfg_val 456 | # "${EASYTLS_SED}" -i -e \ 457 | # "s\`^${cfg_opt}[[:blank:]]=[[:blank:]].*$\`${cfg_opt} = ${cfg_val}\`g" \ 458 | # "${EASYTLS_CONFIG_FILE}" || { 459 | # error_msg "config_update - replace error: ${cfg_opt}" 460 | # return 1 461 | # } 462 | # 463 | # # cleanup 464 | # "${EASYTLS_RM}" -f "${EASYTLS_CONFIG_FILE}.tmp" 465 | 466 | 467 | 468 | 469 | 470 | 471 | -------------------------------------------------------------------------------- /dev/easytls-export-libs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | print() { printf "%s\n" "* $*"; } 4 | die() { print "ERROR: $err_msg : $*"; exit 1; } 5 | 6 | # print top part (READ) 7 | p_top () 8 | { 9 | err_msg="p_top: ${begin}" 10 | print_line=1 11 | { 12 | #IFS='' 13 | while read -r line 14 | do 15 | [ $print_line ] && printf '%s\n' "${line}" 16 | [ "${line}" = "${begin}" ] && break 17 | done < "${src_f}" 18 | } > "${src_f}.top" || return 9 19 | unset err_msg line print_line 20 | } 21 | 22 | # insert lib (READ) 23 | p_mid () 24 | { 25 | err_msg="p_mid: ${begin} ${end}" 26 | unset print_line 27 | { 28 | while read -r line 29 | do 30 | [ "${line}" = "${begin}" ] && print_line=1 && continue 31 | [ "${line}" = "${end}" ] && unset print_line 32 | [ $print_line ] && printf '%s\n' "${line}" 33 | : 34 | done < "${lib_f}" 35 | } > "${src_f}.mid" || return 9 36 | unset err_msg line print_line 37 | } 38 | 39 | # print end part (READ) 40 | p_end () 41 | { 42 | err_msg="p_end: ${end}" 43 | unset print_line 44 | { 45 | while read -r line 46 | do 47 | [ "${line}" = "${end}" ] && print_line=1 48 | [ $print_line ] && printf '%s\n' "${line}" 49 | : 50 | done < "${src_f}" 51 | } > "${src_f}.end" || return 9 52 | unset err_msg line print_line 53 | } 54 | 55 | # Combine parts to new 56 | # (WRITE) 57 | f_cat () 58 | { 59 | err_msg="f_cat: ${src_f}" 60 | cp --attributes-only "${src_f}" "${src_f}.new" 61 | cat "${src_f}.top" "${src_f}.mid" "${src_f}.end" >> "${src_f}.new" || \ 62 | die "f_cat: cat" 63 | unset err_msg 64 | } 65 | 66 | # move new to souce 67 | # (WRITE) 68 | f_mv () 69 | { 70 | err_msg="f_mv: ${src_f}" 71 | mv -f "${src_f}.new" "${src_f}" || \ 72 | die "f_mv: mv" 73 | unset err_msg 74 | } 75 | 76 | # delete temp 77 | # (WRITE) 78 | f_rm () 79 | { 80 | err_msg="f_rm: ${src_f}" 81 | rm -f "${src_f}.top" "${src_f}.mid" "${src_f}.end" || \ 82 | die "f_rm: rm" 83 | unset err_msg 84 | } 85 | 86 | export_lib () 87 | { 88 | save_IFS="${IFS}" 89 | IFS='' 90 | 91 | print "export to $src_f" 92 | p_top || return $? 93 | p_mid || return $? 94 | p_end || return $? 95 | f_cat || return $? 96 | f_mv || return $? 97 | f_rm || return $? 98 | 99 | IFS="${save_IFS}" 100 | 101 | } 102 | 103 | ################ 104 | 105 | f_et_top () 106 | { 107 | print_line=1 108 | { 109 | while read -r line 110 | do 111 | [ $print_line ] && printf '%s\n' "${line}" 112 | [ "${line}" = "${begin}" ] && break 113 | done < "${src_et}" 114 | } > "${dst_et1}" || return 9 115 | } 116 | 117 | f_et_mid () 118 | { 119 | unset print_line 120 | { 121 | while read -r line 122 | do 123 | [ "${line}" = "${begin}" ] && print_line=1 && continue 124 | [ "${line}" = "${end_et}" ] && unset print_line 125 | [ $print_line ] && printf '%s\n' "${line}" 126 | : 127 | done < "${src_tl}" 128 | } > "${dst_et2}" || return 9 129 | } 130 | 131 | f_et_end () 132 | { 133 | unset print_line 134 | { 135 | while read -r line 136 | do 137 | [ "${line}" = "${end_et}" ] && print_line=1 138 | [ $print_line ] && printf '%s\n' "${line}" 139 | : 140 | done < "${src_et}" 141 | } > "${dst_et3}" || return 9 142 | } 143 | 144 | f_et_mv () 145 | { 146 | cat "${dst_et1}" "${dst_et2}" "${dst_et3}" >> "${src_et}.new" 147 | mv -f "${src_et}.new" "${src_et}" 148 | rm -f "${dst_et1}" "${dst_et2}" "${dst_et3}" 149 | } 150 | 151 | f_cc_top () 152 | { 153 | print_line=1 154 | { 155 | while read -r line 156 | do 157 | [ $print_line ] && printf '%s\n' "${line}" 158 | [ "${line}" = "${begin}" ] && break 159 | done < "${src_cc}" 160 | } > "${dst_cc1}" || return 9 161 | } 162 | 163 | f_cc_mid () 164 | { 165 | unset print_line 166 | { 167 | while read -r line 168 | do 169 | [ "${line}" = "${begin}" ] && print_line=1 && continue 170 | [ "${line}" = "${end_cc}" ] && unset print_line 171 | [ $print_line ] && printf '%s\n' "${line}" 172 | : 173 | done < "${src_tl}" 174 | } > "${dst_cc2}" || return 9 175 | } 176 | 177 | f_cc_end () 178 | { 179 | unset print_line 180 | { 181 | while read -r line 182 | do 183 | [ "${line}" = "${end_cc}" ] && print_line=1 184 | [ $print_line ] && printf '%s\n' "${line}" 185 | : 186 | done < "${src_cc}" 187 | } > "${dst_cc3}" || return 9 188 | } 189 | 190 | f_cc_mv () 191 | { 192 | cat "${dst_cc1}" "${dst_cc2}" "${dst_cc3}" >> "${src_cc}.new" 193 | mv -f "${src_cc}.new" "${src_cc}" 194 | rm -f "${dst_cc1}" "${dst_cc2}" "${dst_cc3}" 195 | } 196 | 197 | tctip_lib () 198 | { 199 | # easytls-tctip.lib 200 | 201 | begin="#=# 9273398a-5284-4c1f-aec5-d597ceb1d085" 202 | 203 | end_et="#=# 7f97f537-eafd-40c3-8f31-2fee10c12ad3" 204 | end_cc="#=# b66633f8-3746-436a-901f-29638199b187" 205 | 206 | src_tl="./dev/easytls-tctip.lib" 207 | if [ ! -f "${src_tl}" ]; then 208 | echo "Usage: Run this from ./easytls directory" 209 | echo " ./dev/easytls-export-tctip-lib.sh" 210 | exit 1 211 | fi 212 | 213 | src_et="./easytls" 214 | dst_et1="${src_et}.tmp1" 215 | dst_et2="${src_et}.tmp2" 216 | dst_et3="${src_et}.tmp3" 217 | rm -f "${dst_et1}" "${dst_et2}" "${dst_et3}" "${src_et}.new" 218 | cp --attributes-only "${src_et}" "${src_et}.new" 219 | 220 | src_cc="./easytls-client-connect.sh" 221 | dst_cc1="${src_cc}.tmp1" 222 | dst_cc2="${src_cc}.tmp2" 223 | dst_cc3="${src_cc}.tmp3" 224 | rm -f "${dst_cc1}" "${dst_cc2}" "${dst_cc3}" "${src_cc}.new" 225 | cp --attributes-only "${src_cc}" "${src_cc}.new" 226 | 227 | save_IFS="${IFS}" 228 | IFS='' 229 | 230 | # Old way 231 | 232 | print "tctip library" 233 | 234 | print "easytls" 235 | f_et_top || return 11 236 | f_et_mid || return 12 237 | f_et_end || return 13 238 | f_et_mv || return 14 239 | 240 | print "easytls-client-connect.sh" 241 | f_cc_top || return 21 242 | f_cc_mid || return 22 243 | f_cc_end || return 23 244 | f_cc_mv || return 24 245 | 246 | IFS="${save_IFS}" 247 | } 248 | 249 | ################# 250 | 251 | tctip_lib || die "tctip_lib: $?" 252 | 253 | # New way 254 | lib_f="./dev/easytls-metadata.lib" 255 | print "$lib_f" 256 | begin="#=# 35579017-b084-4d6b-94d5-76397c2d4a1f" 257 | end="#=# 70b4ec32-f1fc-47fb-a261-f02e7f572b62" 258 | 259 | for src_f in easytls \ 260 | easytls-cryptv2-verify.sh \ 261 | easytls-client-connect.sh \ 262 | 263 | do 264 | export_lib || die "export_lib: $lib_f / $src_f" 265 | done 266 | -------------------------------------------------------------------------------- /dev/easytls-metadata.lib: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright - negotiable 4 | # 5 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 6 | # easytls-metadata.lib -- Process TLS-Crypt-V2 Key metadata. 7 | # 8 | # Copyright (C) 2020 Richard Bonhomme (Friday 13th of March 2020) 9 | # https://github.com/TinCanTech/easy-tls 10 | # tincantech@protonmail.com 11 | # All Rights reserved. 12 | # 13 | # This code is released under version 2 of the GNU GPL 14 | # See LICENSE of this project for full licensing details. 15 | # 16 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 17 | # 18 | 19 | # Loaded message 20 | easytls_metadata_lib_ver () 21 | { 22 | [ -z "${EASYTLS_SILENT}" ] || return 0 23 | [ -n "${EASYTLS_VERBOSE}" ] || return 0 24 | # shellcheck disable=2154 25 | "${EASYTLS_PRINTF}" '%s\n' "* easytls-metadata.lib v2.8 loaded" 26 | } # => easytls_tctip_lib_ver () 27 | 28 | #=# 35579017-b084-4d6b-94d5-76397c2d4a1f 29 | 30 | # Break metadata_string into variables 31 | # shellcheck disable=SC2034 # foo appears unused. Verify it or export it. 32 | metadata_string_to_vars () 33 | { 34 | MD_TLSKEY_SERIAL="${1%%-*}" || return 1 35 | 36 | #seed="${*}" || return 1 37 | #MD_SEED="${seed#*-}" || return 1 38 | #unset -v seed 39 | 40 | #md_padding="${md_seed%%--*}" || return 1 41 | md_easytls_ver="${1#*--}" || return 1 42 | MD_EASYTLS="${md_easytls_ver%-*}" || return 1 43 | unset -v md_easytls_ver 44 | 45 | MD_IDENTITY="${2%%-*}" || return 1 46 | MD_SRV_NAME="${2##*-}" || return 1 47 | MD_x509_SERIAL="${3}" || return 1 48 | MD_DATE="${4}" || return 1 49 | MD_CUSTOM_G="${5}" || return 1 50 | MD_NAME="${6}" || return 1 51 | MD_SUBKEY="${7}" || return 1 52 | MD_OPT="${8}" || return 1 53 | MD_FILTERS="${9}" || return 1 54 | } # => metadata_string_to_vars () 55 | 56 | # Break metadata string at delimeter: New Newline, old space 57 | # shellcheck disable=SC2034 # foo appears unused. Verify it or export it. 58 | metadata_stov_safe () 59 | { 60 | [ -n "$1" ] || return 1 61 | input="$1" 62 | 63 | # Not using IFS 64 | err_msg="Unspecified delimiter" 65 | delim_save="${delimiter}" 66 | delimiter="${delimiter:-${newline}}" 67 | [ -n "${delimiter}" ] || return 1 68 | case "${input}" in 69 | *"${delimiter}"*) : ;; 70 | *) delimiter=' ' 71 | esac 72 | 73 | MD_SEED="${input#*-}" 74 | 75 | # Expansions inside ${..} need to be quoted separately, 76 | # otherwise they will match as a pattern. 77 | # Which is the required behaviour. 78 | # shellcheck disable=SC2295 79 | { # Required group for shellcheck 80 | m1="${input%%${delimiter}*}" 81 | input="${input#*${delimiter}}" 82 | m2="${input%%${delimiter}*}" 83 | input="${input#*${delimiter}}" 84 | m3="${input%%${delimiter}*}" 85 | input="${input#*${delimiter}}" 86 | m4="${input%%${delimiter}*}" 87 | input="${input#*${delimiter}}" 88 | m5="${input%%${delimiter}*}" 89 | input="${input#*${delimiter}}" 90 | m6="${input%%${delimiter}*}" 91 | input="${input#*${delimiter}}" 92 | m7="${input%%${delimiter}*}" 93 | input="${input#*${delimiter}}" 94 | m8="${input%%${delimiter}*}" 95 | input="${input#*${delimiter}}" 96 | m9="${input%%${delimiter}*}" 97 | input="${input#*${delimiter}}" 98 | } 99 | 100 | # An extra space has been used, probably in the name 101 | err_msg="metadata-lib: ${m9} vs ${input}" 102 | [ "${m9}" = "${input}" ] || return 1 103 | 104 | delimiter="${delim_save}" 105 | 106 | err_msg="metadata-lib: metadata_string_to_vars" 107 | metadata_string_to_vars "$m1" "$m2" "$m3" "$m4" \ 108 | "$m5" "$m6" "$m7" "$m8" "$m9" || return 1 109 | unset -v m1 m2 m3 m4 m5 m6 m7 m8 m9 input err_msg 110 | } # => metadata_stov_safe () 111 | 112 | #=# 70b4ec32-f1fc-47fb-a261-f02e7f572b62 113 | -------------------------------------------------------------------------------- /dev/easytls-op-test.bat: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | 3 | REM VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 4 | REM Easy-TLS -- A Shell-based Easy-RSA extension utility to help manage 5 | REM * OpenVPN specific TLS keys 6 | REM * Easy-RSA based x509 security credentials 7 | REM * Verified 'inline' combined OpenVPN node packages 8 | REM 9 | REM Copyright (C) 2020 Richard Bonhomme (Friday 13th of March 2020) 10 | REM https://github.com/TinCanTech/easy-tls 11 | REM tincantech@protonmail.com 12 | REM All Rights reserved. 13 | REM 14 | REM This code is released under version 2 of the GNU GPL 15 | REM See LICENSE of this project for full licensing details. 16 | REM 17 | REM VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 18 | 19 | set 20 | 21 | mkdir "0 0" 22 | cd "0 0" 23 | 24 | copy ..\easytls 25 | copy ..\easytls-cryptv2-verify.sh 26 | copy ..\easytls-cryptv2-verify.vars-example 27 | copy ..\easytls-client-connect.sh 28 | copy ..\easytls-client-connect.vars-example 29 | copy ..\easytls-client-disconnect.sh 30 | copy ..\easytls-client-disconnect.vars-example 31 | copy ..\easytls-conntrac.lib 32 | 33 | cd 34 | dir 35 | 36 | mkdir "dev" 37 | cd "dev" 38 | 39 | copy ..\..\dev\easytls-unit-tests.sh 40 | copy ..\..\dev\easytls-metadata.lib 41 | copy ..\..\dev\easytls-tctip.lib 42 | copy ..\..\dev\easytls-shellcheck.sh 43 | copy ..\..\dev\et-tdir1.tar 44 | copy ..\..\dev\et-tdir2.tar 45 | copy ..\..\dev\et-tdir3.tar 46 | 47 | cd 48 | dir 49 | 50 | cd .. 51 | 52 | if %PROCESSOR_ARCHITECTURE% == x86 ( 53 | curl -LO https://github.com/OpenVPN/easy-rsa/releases/download/v3.1.6/EasyRSA-3.1.6-win32.zip 54 | 7z e -aoa EasyRSA-3.1.6-win32.zip 55 | REM ping -n 10 127.0.0.1 56 | curl -LO https://github.com/TinCanTech/Prebuilt-Openvpn/raw/master/wovpn/wovpn32b.zip 57 | 7z e -aoa wovpn32b.zip 58 | ) ELSE ( 59 | curl -LO https://github.com/OpenVPN/easy-rsa/releases/download/v3.1.6/EasyRSA-3.1.6-win64.zip 60 | 7z e -aoa EasyRSA-3.1.6-win64.zip 61 | REM ping -n 10 127.0.0.1 62 | curl -LO https://github.com/TinCanTech/Prebuilt-Openvpn/raw/master/wovpn/wovpn64b.zip 63 | 7z e -aoa wovpn64b.zip 64 | ) 65 | 66 | REM curl -LO https://raw.githubusercontent.com/TinCanTech/easyrsa-plus/master/easyrsa3/easyrsa 67 | 68 | SET PATH=%PATH%;.\ 69 | SET HOME=%PATH% 70 | SET ENV=/disable-env 71 | REM SET EASYTLS_REMOTE_CI=1 72 | SET SHALLOW=1 73 | SET EASYTLS_base_dir=. 74 | SET EASYTLS_tmp_dir=./easytls-unit-tests 75 | SET EASYTLS_ersabin_dir=. 76 | SET EASYTLS_ovpnbin_dir=. 77 | 78 | cd 79 | dir 80 | 81 | sh.exe dev\easytls-unit-tests.sh 82 | 83 | IF ERRORLEVEL 0 SET SH_EXIT=0 84 | IF ERRORLEVEL 1 SET SH_EXIT=1 85 | 86 | ECHO SH_EXIT: %SH_EXIT% 87 | EXIT /B %SH_EXIT% 88 | 89 | -------------------------------------------------------------------------------- /dev/easytls-op-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright - negotiable 4 | copyright () 5 | { 6 | : << VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 7 | # easytls-op-test.sh -- Remote CI unit test launcher 8 | # 9 | # Copyright (C) 2020 Richard Bonhomme (Friday 13th of March 2020) 10 | # https://github.com/TinCanTech/easy-tls 11 | # tincantech@protonmail.com 12 | # All Rights reserved. 13 | # 14 | # This code is released under version 2 of the GNU GPL 15 | # See LICENSE of this project for full licensing details. 16 | # 17 | VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 18 | } 19 | 20 | dl_ossl3 () 21 | { 22 | file="apps/openssl" 23 | source="TinCanTech/pre-built-openssl-3/master" 24 | host="https://raw.githubusercontent.com" 25 | 26 | printf '%s\n\n' "* curl -SO ${host}/${source}/${file}" 27 | curl -SO "${host}/${source}/${file}" || \ 28 | die "Failed to download $file, error: $?" 29 | 30 | OSSL_V3_LIBB="${PWD}/openssl" 31 | 32 | printf '%s\n\n' "* chmod +x openssl" 33 | chmod +x openssl 34 | 35 | "${OSSL_V3_LIBB}" version || die "openssl version: ${OSSL_V3_LIBB}" 36 | } 37 | 38 | env 39 | 40 | etls_ut_file_list="easytls 41 | easytls-cryptv2-verify.sh 42 | examples/easytls-cryptv2-verify.vars-example 43 | easytls-client-connect.sh 44 | examples/easytls-client-connect.vars-example 45 | easytls-client-disconnect.sh 46 | examples/easytls-client-disconnect.vars-example 47 | easytls-conntrac.lib 48 | dev/easytls-unit-tests.sh 49 | dev/easytls-metadata.lib 50 | dev/easytls-tctip.lib 51 | dev/easytls-shellcheck.sh 52 | dev/et-tdir1.tar 53 | dev/et-tdir2.tar 54 | dev/et-tdir3.tar" 55 | 56 | etls_ut_dir_name='./0 0' 57 | 58 | mkdir -p "${etls_ut_dir_name}/dev" "${etls_ut_dir_name}/examples" 59 | 60 | for f in ${etls_ut_file_list}; do 61 | cp -v "./${f}" "${etls_ut_dir_name}/${f}" 62 | done 63 | 64 | cd "${etls_ut_dir_name}" 65 | 66 | #dl_ossl3 67 | 68 | CURL_TARGET="https://raw.githubusercontent.com/TinCanTech/easy-rsa/master/easyrsa3/easyrsa" 69 | curl -O "$CURL_TARGET" || exit 77 70 | 71 | CURL_TARGET="https://raw.githubusercontent.com/TinCanTech/easy-rsa/master/easyrsa3/openssl-easyrsa.cnf" 72 | curl -O "$CURL_TARGET" || exit 77 73 | 74 | CURL_TARGET="https://raw.githubusercontent.com/TinCanTech/Prebuilt-OpenVPN/master/src/openvpn/openvpn" 75 | curl -O "$CURL_TARGET" || exit 77 76 | 77 | echo 78 | 79 | for f in ./easyrsa ./openssl-easyrsa.cnf ./openvpn 80 | do 81 | if [ -f "${f}" ]; 82 | then 83 | chmod 744 "${f}" 84 | else 85 | echo "Failed to DL ${f}" 86 | exit 71 87 | fi 88 | done 89 | 90 | pwd 91 | ls -l 92 | 93 | #export EASYTLS_REMOTE_CI=1 94 | export SHALLOW=1 95 | 96 | export EASYTLS_OPENVPN="./openvpn" 97 | printf "%s\n" "EASYTLS_OPENVPN=$EASYTLS_OPENVPN" 98 | 99 | #export EASYRSA_OPENSSL="./openssl" 100 | export EASYRSA_OPENSSL="openssl" 101 | printf "%s\n" "EASYRSA_OPENSSL=$EASYRSA_OPENSSL" 102 | 103 | $EASYTLS_OPENVPN --version 104 | 105 | sh ./dev/easytls-shellcheck.sh || exit 9 106 | 107 | sh ./dev/easytls-unit-tests.sh || exit 9 108 | 109 | cd .. 110 | rm -rf "${etls_ut_dir_name}" 111 | -------------------------------------------------------------------------------- /dev/easytls-openvpn.diff: -------------------------------------------------------------------------------- 1 | diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c 2 | index 103e882e..71c62b06 100644 3 | --- a/src/openvpn/multi.c 4 | +++ b/src/openvpn/multi.c 5 | @@ -1729,6 +1729,9 @@ multi_client_connect_setenv(struct multi_context *m, 6 | /* setenv incoming cert common name for script */ 7 | setenv_str(mi->context.c2.es, "common_name", tls_common_name(mi->context.c2.tls_multi, true)); 8 | 9 | + /* setenv peer_id */ 10 | + setenv_int(mi->context.c2.es, "peer_id", mi->context.c2.tls_multi->peer_id); 11 | + 12 | /* setenv client real IP address */ 13 | setenv_trusted(mi->context.c2.es, get_link_socket_info(&mi->context)); 14 | 15 | -------------------------------------------------------------------------------- /dev/easytls-shellcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | shellcheck_bin='shellcheck' 4 | [ -f '../shellcheck' ] && shellcheck_bin='../shellcheck' 5 | #[ -f "${shellcheck_bin}" ] || { 6 | # echo "shellcheck binary not found" 7 | # exit 1 8 | # } 9 | 10 | #"${shellcheck_bin}" --version || { echo 'croak!' && exit 1; } 11 | 12 | SHELLCHECK_FIXED_OPTS="--shell=sh -x" 13 | unset raw 14 | # shell-o check-o doesn't have -v 15 | case "${1}" in 16 | -v) 17 | shift 18 | SHELLCHECK_OPTS="${SHELLCHECK_FIXED_OPTS}" 19 | ;; 20 | -vv) 21 | shift 22 | SHELLCHECK_OPTS="${SHELLCHECK_FIXED_OPTS} -o all" 23 | ;; 24 | -vvv) 25 | shift 26 | SHELLCHECK_OPTS="-x -o all" 27 | ;; 28 | -r) 29 | shift 30 | raw=1 31 | ;; 32 | '') 33 | SHELLCHECK_OPTS="${SHELLCHECK_FIXED_OPTS} -S warning" 34 | ;; 35 | *) 36 | SHELLCHECK_OPTS="${SHELLCHECK_FIXED_OPTS}" 37 | ;; 38 | esac 39 | 40 | # || [ $EASYTLS_VERBOSE ] 41 | 42 | 43 | # Permanently silence 44 | # SC2016 (info): 45 | # Expressions don't expand in single quotes, use double quotes for that 46 | # eg. "${EASYTLS_AWK}" '{print $2}' 47 | # seen as a likely error but this information is not needed 48 | # 49 | # SC2086 (info): Removed 50 | # Double quote to prevent globbing and word splitting. 51 | # eg '[ $log_line ] ] || bar' (the extra ']' is not seen if log_line is not quoted) 52 | # Double quote everything or get hoisted! I will fix this.. 53 | PERMA_FROST="-e 2016" 54 | [ -z "${PERMA_FROST}" ] || SHELLCHECK_OPTS="${SHELLCHECK_OPTS} ${PERMA_FROST}" 55 | 56 | # Others: 57 | # SC2250 (style): 58 | # Prefer putting braces around variable references even when not strictly required. 59 | # SC2248 (style): 60 | # Prefer double quoting even when variables don't contain special characters. 61 | # SC2244 (style): 62 | # Prefer explicit -n to check non-empty string (or use =/-ne to check boolean/integer 63 | OPTION_FROST="-e 2244,2248,2250" 64 | [ -z "${OPTION_FROST}" ] || SHELLCHECK_OPTS="${SHELLCHECK_OPTS} ${OPTION_FROST}" 65 | 66 | # Disable at will 67 | #[ -z "${FROST_BITE}" ] || SHELLCHECK_OPTS="${SHELLCHECK_OPTS} ${FROST_BITE}" 68 | 69 | # Append command line, use -i not -o 70 | [ -z "$*" ] || SHELLCHECK_OPTS="${SHELLCHECK_OPTS} $*" 71 | 72 | # Mode: shellcheck 'raw' 73 | [ -z "${raw}" ] || SHELLCHECK_OPTS="${SHELLCHECK_FIXED_OPTS} $*" 74 | 75 | # Final export 76 | export SHELLCHECK_OPTS 77 | 78 | log_line='========================================================================' 79 | 80 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls' 81 | "${shellcheck_bin}" ./easytls || \ 82 | sc_easytls=1 83 | 84 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-cryptv2-verify.sh' 85 | "${shellcheck_bin}" ./easytls-cryptv2-verify.sh || \ 86 | sc_easytls_cryptv2_verify=1 87 | 88 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-cryptv2-verify.vars-example' 89 | "${shellcheck_bin}" --shell=sh ./examples/easytls-cryptv2-verify.vars-example || \ 90 | sc_easytls_cryptv2_verify_vars=1 91 | 92 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-client-connect.sh' 93 | "${shellcheck_bin}" ./easytls-client-connect.sh || \ 94 | sc_easytls_client_connect=1 95 | 96 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-client-connect.vars-example' 97 | "${shellcheck_bin}" --shell=sh ./examples/easytls-client-connect.vars-example || \ 98 | sc_easytls_client_connect_vars=1 99 | 100 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-client-disconnect.sh' 101 | "${shellcheck_bin}" ./easytls-client-disconnect.sh || \ 102 | sc_easytls_client_disconnect=1 103 | 104 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-client-disconnect.vars-example' 105 | "${shellcheck_bin}" --shell=sh ./examples/easytls-client-disconnect.vars-example || \ 106 | sc_easytls_client_disconnect_vars=1 107 | 108 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-metadata.lib' 109 | "${shellcheck_bin}" ./dev/easytls-metadata.lib || \ 110 | sc_easytls_metadata=1 111 | 112 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-tctip.lib' 113 | "${shellcheck_bin}" ./dev/easytls-tctip.lib || \ 114 | sc_easytls_tctip=1 115 | 116 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-conntrac.lib' 117 | "${shellcheck_bin}" ./easytls-conntrac.lib || \ 118 | sc_easytls_conntrac=1 119 | 120 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-unit-tests.sh' 121 | "${shellcheck_bin}" ./dev/easytls-unit-tests.sh || \ 122 | sc_easytls_unit_tests=1 123 | 124 | printf '\n%s\n%s\n' "$log_line" '*** shellcheck easytls-shellcheck.sh' 125 | "${shellcheck_bin}" ./dev/easytls-shellcheck.sh || \ 126 | sc_easytls_shellcheck=1 127 | 128 | printf '\n%s\n' "$log_line" 129 | exit_status=$(( sc_easytls + \ 130 | sc_easytls_cryptv2_verify + \ 131 | sc_easytls_client_connect + \ 132 | sc_easytls_client_disconnect + \ 133 | sc_easytls_cryptv2_verify_vars + \ 134 | sc_easytls_client_connect_vars + \ 135 | sc_easytls_client_disconnect_vars + \ 136 | sc_easytls_metadata + \ 137 | sc_easytls_tctip + \ 138 | sc_easytls_conntrac + \ 139 | sc_easytls_unit_tests + \ 140 | sc_easytls_shellcheck \ 141 | )) 142 | 143 | # easytls version 144 | ./easytls version || { echo 'croak!' && exit 1; } 145 | 146 | # exit status 147 | [ "${exit_status}" -eq 0 ] || printf ' %s\n\n' \ 148 | "***ERROR*** Easy-TLS Shellcheck exit status: $exit_status (of 12)" 149 | 150 | # options 151 | printf '%s\n\n' "SHELLCHECK_OPTS: ${SHELLCHECK_OPTS:-===[ No Options ]===}" 152 | 153 | # version 154 | unset SHELLCHECK_OPTS # or get more errors 155 | "${shellcheck_bin}" --version || { echo 'vroak!' && exit 1; } 156 | 157 | # raw 158 | if [ -n "${raw}" ] && [ "${exit_status}" -ne 0 ]; then 159 | printf "\n* raw mode * Expect weird stuff and ERRORS\n\n" 160 | fi 161 | -------------------------------------------------------------------------------- /dev/easytls-tctip.lib: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright - negotiable 4 | # 5 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 6 | # easytls-tctip.lib - IPv4/6 address functions 7 | # 8 | # Copyright (C) 2020 Richard Bonhomme (Friday 13th of March 2020) 9 | # https://github.com/TinCanTech/easy-tls 10 | # tincantech@protonmail.com 11 | # All Rights reserved. 12 | # 13 | # This code is released under version 2 of the GNU GPL 14 | # See LICENSE of this project for full licensing details. 15 | # 16 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 17 | # 18 | 19 | # Loaded message 20 | easytls_tctip_lib_ver () 21 | { 22 | [ -z "${EASYTLS_SILENT}" ] || return 0 23 | [ -n "${EASYTLS_VERBOSE}" ] || return 0 24 | # shellcheck disable=2154 25 | "${EASYTLS_PRINTF}" '%s\n' "* easytls-tctip.lib v2.8 loaded" 26 | } # => easytls_tctip_lib_ver () 27 | 28 | #=# 9273398a-5284-4c1f-aec5-d597ceb1d085 29 | 30 | # Verbose message 31 | verbose_easytls_tctip_lib () 32 | { 33 | [ -z "${EASYTLS_SILENT}" ] || return 0 34 | [ -n "${EASYTLS_TCTIP_LIB_VERBOSE}" ] || return 0 35 | "${EASYTLS_PRINTF}" '%s\n' "${1}" 36 | } # => verbose_easytls_tctip_lib () 37 | 38 | # Front end validate IP address 39 | validate_ip_address () 40 | { 41 | [ "${1}" = "${1%%.*}" ] || ipv4=1 42 | [ "${1}" = "${1%%:*}" ] || ipv6=1 43 | [ -n "${ipv4}${ipv6}" ] || return 1 44 | if [ -n "${ipv4}" ] && [ -n "${ipv6}" ]; then 45 | easytls_verbose "Unsupported <:Port>" 46 | return 1 47 | fi 48 | [ -n "${ipv4}" ] && validate_ip4_data "$@" && valid4=1 49 | [ -n "${ipv6}" ] && validate_ip6_data "$@" && valid6=1 50 | [ -n "${valid4}" ] && [ -n "${valid6}" ] && return 1 51 | [ -z "${valid4}" ] && [ -z "${valid6}" ] && return 1 52 | } # => validate_ip_address () 53 | 54 | # Exit with error 55 | invalid_address () 56 | { 57 | case "${1}" in 58 | 1) print "easytls invalid" ;; 59 | 10) print "excess input" ;; 60 | 11) print "illegal format" ;; 61 | 12) print "illegal mask" ;; 62 | 13) print "mask range" ;; 63 | 14) print "leading zero" ;; 64 | 15) print "class range" ;; 65 | 16) print "class count" ;; 66 | 17) print "cidr mask" ;; 67 | 18) print "input error" ;; 68 | 19) print "ip2dec error" ;; 69 | 20) 70 | print "ip6/mask-length mismatch" 71 | print "ip6/mask correct example: 1:22:333:4444:5::/80" 72 | ;; 73 | *) print "undocumented ${1} ?" ;; 74 | esac 75 | } # => invalid_address () 76 | 77 | # IPv4 address to decimal 78 | ip2dec () 79 | { 80 | case "${1}" in 81 | *[!1234567890.]* | .* | *. | *..* ) return 1 ;; 82 | *.*.*.* ) : ;; #OK 83 | * ) return 1 ;; 84 | esac 85 | 86 | temp_ip_addr="${1}" 87 | a="${temp_ip_addr%%.*}"; temp_ip_addr="${temp_ip_addr#*.}" 88 | b="${temp_ip_addr%%.*}"; temp_ip_addr="${temp_ip_addr#*.}" 89 | c="${temp_ip_addr%%.*}"; temp_ip_addr="${temp_ip_addr#*.}" 90 | d="${temp_ip_addr%%.*}" 91 | 92 | for i in "${a}" "${b}" "${c}" "${d}"; do 93 | [ "${#i}" -gt 1 ] || continue 94 | [ -n "${i%%0*}" ] || return 1 95 | if [ 0 -gt "${i}" ] || [ "${i}" -gt 255 ]; then return 1; fi 96 | done 97 | ip4_dec="$(( (a << 24) + (b << 16) + (c << 8) + d ))" || return 1 98 | unset -v temp_ip_addr a b c d 99 | } # => ip2dec () 100 | 101 | # IPv4 CIDR mask length to decimal 102 | cidrmask2dec () 103 | { 104 | mask_dec=0 105 | imsk_dec=0 106 | count=32 # or 128 - If possible.. 107 | power=1 108 | while [ "${count}" -gt 0 ]; do 109 | count="$(( count - 1 ))" 110 | if [ "${1}" -gt "${count}" ]; then 111 | # mask 112 | mask_dec="$(( mask_dec + power ))" 113 | else 114 | # inverse 115 | imsk_dec="$(( imsk_dec + power ))" 116 | fi 117 | power="$(( power * 2 ))" 118 | done 119 | unset -v count power 120 | } # => cidrmask2dec () 121 | 122 | # EXPAND IPv6 123 | expand_ip6_address () 124 | { 125 | [ -z "${2}" ] || return 10 126 | in_ip_addr="${1}" 127 | shift 128 | 129 | in_valid_hextets="${in_ip_addr%/*}" 130 | in_valid_mask_len="${in_ip_addr##*/}" 131 | unset -v in_ip_addr 132 | 133 | # mask length 134 | case "${in_valid_mask_len}" in 135 | "${in_valid_hextets}" | '' ) in_valid_mask_len=128 ;; 136 | [!1234567890] | 0* ) return 11 ;; 137 | * ) : # OK 138 | esac 139 | if [ 0 -gt "${in_valid_mask_len}" ] || [ "${in_valid_mask_len}" -gt 128 ] 140 | then 141 | return 11 142 | fi 143 | 144 | # ADDRESS 6 145 | temp_valid_hextets="${in_valid_hextets}" 146 | 147 | # expand leading colon 148 | [ "${temp_valid_hextets}" = "${temp_valid_hextets#:}" ] || \ 149 | lead_colon=1 150 | [ -z "${lead_colon}" ] || temp_valid_hextets="0${temp_valid_hextets}" 151 | 152 | # Count valid compressed hextets 153 | count_valid_hextets=0 154 | while [ -n "${temp_valid_hextets}" ]; do 155 | count_valid_hextets="$(( count_valid_hextets + 1 ))" 156 | if [ "${temp_valid_hextets}" = "${temp_valid_hextets#*:}" ]; then 157 | temp_valid_hextets="${temp_valid_hextets}:" 158 | fi 159 | temp_valid_hextets="${temp_valid_hextets#*:}" 160 | temp_valid_hextets="${temp_valid_hextets#:}" 161 | done 162 | verbose_easytls_tctip_lib "count_valid_hextets: ${count_valid_hextets}" 163 | 164 | # expand double colon 165 | temp_valid_hextets="${in_valid_hextets}" 166 | expa_valid_hextets="${in_valid_hextets}" 167 | if [ "${count_valid_hextets}" -lt 8 ]; then 168 | hi_part="${temp_valid_hextets%::*}" 169 | lo_part="${temp_valid_hextets#*::}" 170 | missing_zeros="$(( 8 - count_valid_hextets ))" 171 | while [ "${missing_zeros}" -gt 0 ]; do 172 | hi_part="${hi_part}:0" 173 | missing_zeros="$(( missing_zeros - 1 ))" 174 | done 175 | unset -v missing_zeros 176 | expa_valid_hextets="${hi_part}:${lo_part}" 177 | # Re-expand leading colon 178 | [ -z "${lead_colon}" ] || expa_valid_hextets="0${expa_valid_hextets}" 179 | fi 180 | # Save the orangutan 181 | unset -v lead_colon lo_part hi_part count_valid_hextets 182 | verbose_easytls_tctip_lib "expa_valid_hextets: ${expa_valid_hextets}" 183 | 184 | temp_valid_hextets="${expa_valid_hextets}" 185 | hex_count=8 186 | unset -v full_valid_hextets delim 187 | # Expand compressed zeros 188 | while [ "${hex_count}" -gt 0 ]; do 189 | hextet="${temp_valid_hextets%%:*}" 190 | while [ "${#hextet}" -lt 4 ]; do 191 | hextet="0${hextet}" 192 | done 193 | full_valid_hextets="${full_valid_hextets}${delim}${hextet}" 194 | delim=':' 195 | temp_valid_hextets="${temp_valid_hextets#*:}" 196 | hex_count="$(( hex_count - 1 ))" 197 | done 198 | # Save "The violence inherent in the system" 199 | unset -v hex_count delim 200 | verbose_easytls_tctip_lib "full_valid_hextets: ${full_valid_hextets}" 201 | 202 | # Split IP at mask_len 203 | [ "$(( in_valid_mask_len % 4 ))" -eq 0 ] || \ 204 | die "in_valid_mask_len % 4: ${in_valid_mask_len}" 205 | hex_mask="$(( in_valid_mask_len / 4 ))" 206 | 207 | temp_valid_hextets="${full_valid_hextets}" 208 | while [ "${hex_mask}" -gt 0 ]; do 209 | delete_mask="${temp_valid_hextets#?}" 210 | verbose_easytls_tctip_lib "delete_mask: ${delete_mask}" 211 | hex_char="${temp_valid_hextets%"${delete_mask}"}" 212 | verbose_easytls_tctip_lib "hex_char: ${hex_char}" 213 | temp_valid_hextets="${temp_valid_hextets#?}" 214 | verbose_easytls_tctip_lib "temp_valid_hextets: ${temp_valid_hextets}" 215 | full_subnet_addr6="${full_subnet_addr6}${hex_char}" 216 | verbose_easytls_tctip_lib "full_subnet_addr6: ${full_subnet_addr6}" 217 | [ "${hex_char}" = ':' ] || hex_mask="$(( hex_mask - 1 ))" 218 | verbose_easytls_tctip_lib "*** hex_mask: ${hex_mask}" 219 | done 220 | # Save the polar ice-caps 221 | unset -v hex_char hex_mask delete_mask 222 | 223 | # The remainder should equal zero 224 | while [ -n "${temp_valid_hextets}" ]; do 225 | hextet="${temp_valid_hextets%%:*}" 226 | if [ -z "${hextet}" ]; then 227 | temp_valid_hextets="${temp_valid_hextets#*:}" 228 | hextet="${temp_valid_hextets%%:*}" 229 | fi 230 | 231 | if [ "${temp_valid_hextets}" = "${temp_valid_hextets#*:}" ]; then 232 | temp_valid_hextets="${temp_valid_hextets}:" 233 | fi 234 | temp_valid_hextets="${temp_valid_hextets#*:}" 235 | 236 | # shellcheck disable=SC2249 # (info): default *) case 237 | case "${hextet}" in 238 | *[!0:]* ) return 20 ;; 239 | esac 240 | done 241 | verbose_easytls_tctip_lib "full_valid_hextets: ${full_valid_hextets}" 242 | verbose_easytls_tctip_lib "full_subnet_addr6: ${full_subnet_addr6}" 243 | verbose_easytls_tctip_lib "temp_valid_hextets: ${temp_valid_hextets}" 244 | # Save the trees 245 | unset -v hextet temp_valid_hextets 246 | # Return full_valid_hextets full_subnet_addr6 247 | } # => expand_ip6_address () 248 | 249 | #=# b66633f8-3746-436a-901f-29638199b187 250 | 251 | # EXPAND IPv4 252 | # This tests that the subnet/mask are "equivalent" 253 | expand_ip4_address () 254 | { 255 | validate_ip4_data "$@" || die "$* - validate_ip4_data - expand_ip4_address" 256 | # Verify IP matches mask (eg: 1.2.3.0/24 ok, 1.2.3.4/24 bad) 257 | temp_a4andm_dec="$(( temp_ip4_addr_dec & temp_ip4_mask_dec ))" 258 | [ "${temp_a4andm_dec}" -eq "${temp_ip4_addr_dec}" ] && return 0 259 | } # => expand_ip4_address () 260 | 261 | # Validate IPv4 data 262 | validate_ip4_data () 263 | { 264 | [ -z "${2}" ] || return 10 265 | temp_ip_addr="${1}" 266 | 267 | # Syntax 268 | case "${temp_ip_addr}" in 269 | *[!0123456789./]* | .* | *. | *..* | */*.* ) return 11 ;; 270 | *.*.*.* ) : ;; #OK 271 | * ) return 1 ;; 272 | esac 273 | 274 | # Netmask 275 | mask_len="${temp_ip_addr##*/}" 276 | if [ "${mask_len}" = "${temp_ip_addr}" ]; then 277 | mask_len=32 278 | else 279 | temp_ip_addr="${temp_ip_addr%/*}" 280 | [ -n "${mask_len}" ] || return 12 281 | [ -n "${mask_len%%0*}" ] || return 12 282 | if [ "${mask_len}" -lt 0 ] || [ "${mask_len}" -gt 32 ]; then 283 | return 13 284 | fi 285 | fi 286 | 287 | # Valid mask to decimal 288 | cidrmask2dec "${mask_len}" || return 17 289 | temp_ip4_mask_dec="${mask_dec}" 290 | #key_ip4_imsk_dec="${imsk_dec}" 291 | unset -v mask_dec imsk_dec 292 | 293 | # Address 294 | unset -v valid_octets delim 295 | i=0 296 | while [ -n "${temp_ip_addr}" ]; do 297 | i=$(( i + 1 )) 298 | octet="${temp_ip_addr%%.*}" 299 | 300 | if [ "${octet}" != "${octet#0}" ]; then 301 | [ "${octet}" = "0" ] || return 14 302 | fi 303 | 304 | if [ "${octet}" -lt 0 ] || [ "${octet}" -gt 255 ]; then 305 | return 15 306 | fi 307 | 308 | valid_octets="${valid_octets}${delim}${octet}" 309 | delim='.' 310 | 311 | # Break after last octet 312 | [ "${temp_ip_addr}" != "${temp_ip_addr#*.}" ] || break 313 | 314 | # Drop the left most "$octet." 315 | temp_ip_addr="${temp_ip_addr#*.}" 316 | done 317 | # *.*.*.* four octets? 318 | [ "${i}" -eq 4 ] || return 16 319 | unset -v temp_ip_addr delim octet i 320 | 321 | # Valid IPv4 to decimal 322 | ip2dec "${valid_octets}" || return 19 323 | temp_ip4_addr_dec="${ip4_dec}" 324 | unset -v ip4_dec 325 | # Return: temp_ip4_addr_dec ; temp_ip4_mask_dec ; valid_octets ; mask_len 326 | } # => validate_ip4_data () 327 | 328 | # Validate IPv6 data 329 | validate_ip6_data () 330 | { 331 | [ -z "${2}" ] || return 10 332 | temp_ip_addr="${1}" 333 | 334 | # Syntax 335 | case "${temp_ip_addr}" in 336 | #:[!:]* ) return 11 ;; 337 | *[!:]: ) return 11 ;; 338 | *[!:]:/* ) return 11 ;; 339 | *::*::* ) return 11 ;; 340 | */*:* ) return 11 ;; 341 | *[!0123456789abcdef:/]* ) return 11 ;; 342 | *) : # OK 343 | esac 344 | 345 | # Netmask 346 | unset -v valid_mask_len 347 | mask_len="${temp_ip_addr##*/}" 348 | if [ "${mask_len}" = "${temp_ip_addr}" ]; then 349 | mask_len=128 350 | else 351 | temp_ip_addr="${temp_ip_addr%/*}" 352 | fi 353 | 354 | [ -n "${mask_len}" ] || return 12 355 | # shellcheck disable=SC2249 # (info): default *) case 356 | case "${mask_len}" in 357 | *[!0123456789]* | 0* ) return 11 ;; 358 | esac 359 | if [ "${mask_len}" -lt 0 ] || [ "${mask_len}" -gt 128 ]; then 360 | return 13 361 | fi 362 | valid_mask_len="${mask_len}" 363 | 364 | # Address 365 | unset -v valid_hextets delim 366 | i=0 367 | while [ -n "${temp_ip_addr}" ]; do 368 | i="$(( i + 1 ))" 369 | unset -v hextet 370 | 371 | # Leading : to current string 372 | if [ -z "${temp_ip_addr%%:*}" ]; then 373 | if [ "${i}" -eq 1 ]; then 374 | # Leading single : 375 | # Does not count as double_colon 376 | [ -z "${lead_colon}" ] || return 19 377 | lead_colon=1 378 | hextet=":" 379 | else 380 | # right-hand colon in '::' 381 | # The left-hand colon was stripped with the last hextet 382 | [ -z "${double_colon}" ] || return 17 383 | double_colon=1 384 | hextet=":" 385 | unset -v delim 386 | fi 387 | fi 388 | 389 | # Left to right 390 | temptet="${temp_ip_addr%%:*}" 391 | hextet="${hextet:-${temptet}}" 392 | unset -v temptet 393 | 394 | if [ "${hextet}" = ":" ]; then 395 | # OK 396 | : 397 | else 398 | # Range: 0 < hextet < 65535 399 | if [ 0 -gt "$(( 0x${hextet} ))" ] || \ 400 | [ "$(( 0x${hextet} ))" -gt 65535 ] 401 | then 402 | return 15 403 | fi 404 | fi 405 | 406 | if [ -n "${lead_colon}" ] && [ "${i}" -eq 1 ]; then unset -v hextet; fi 407 | valid_hextets="${valid_hextets}${delim}${hextet}" 408 | delim=':' 409 | 410 | # Break after last hextet 411 | [ "${temp_ip_addr}" != "${temp_ip_addr#*:}" ] || break 412 | 413 | # Drop the left most 'ffff:' not '::' 414 | temp_ip_addr="${temp_ip_addr#*:}" 415 | done 416 | 417 | # shudder 418 | if [ -n "${double_colon}" ]; then 419 | { [ "${i}" -gt 1 ] && [ "${i}" -lt 9 ]; } || return 16 420 | else 421 | [ "${i}" -eq 8 ] || return 16 422 | fi 423 | # Save the atmosphere 424 | unset -v temp_ip_addr delim hextet i double_colon lead_colon 425 | 426 | # "$full_valid_ip6_addr" is not use in easytls-tctip.lib 427 | # shellcheck disable=2034 428 | full_valid_ip6_addr="${valid_hextets}/${valid_mask_len}" 429 | # Return: valid_hextets ; valid_mask_len ; full_valid_ip6_addr 430 | } # => validate_ip6_data () 431 | 432 | #=# 7f97f537-eafd-40c3-8f31-2fee10c12ad3 433 | -------------------------------------------------------------------------------- /doc/easytls-change.log: -------------------------------------------------------------------------------- 1 | https://github.com/TinCanTech/easy-tls 2 | Change log: 3 | 4 | Version 2.8.0 5 | * TBD 6 | Remove 'remove-metadata' 7 | Commit c2a17fe2035b2136fafe121599d9a7c0a13336fb 8 | Completely untested and unnecessary function 9 | Fully integrate upgrade and rehash facilities 10 | Commit 5b024b10099d7ab6cfe0c336be722b2e1fa4e49a 11 | Upgrade older versions and rehash on request 12 | Allow deleting an inline file which fails the HASH 13 | Commit a1a5212b1780e4161894bae6cdc82a59b2cab576 14 | Manually edited inline files are likely, this is easy to use 15 | Default metadata delimiter is now newline 16 | Commit f2b8f841b92fa0b57d576373457675440c55d199 17 | Space is still supported but all new keys will use newline 18 | Allow spaces in PATH 19 | Commit 4cbdd621ee99e328fa2cd139b77742d853c03137 20 | Allow spaces in PATH 21 | 22 | Version 2.7.0 23 | * 2022-01-14 - Commit e6153d9f6d13a2c08afb4cdcc406e50265ad35fe 24 | Switch to fast hash routine 25 | Commit b5baffdf19f23b217a29e4a11dbf8a380b03cb21 26 | This is approximately 28% faster than wiscii_hash 27 | Abandon TLS-Crypt-V2 Server GROUP keys 28 | Commit 4dd0d55ce4f0badba4d387a962fa3ba402508d4b 29 | Add Client-Group keys to standard TLS-Crypt-V2 Server-keys 30 | 31 | Version 2.6.0 32 | * 2021-12-13 - Commit 28936a49805e241ec10c848648aa52675ee7472c 33 | Introduce easytls-tctip.lib (Optional library) 34 | Commit f85e95e4bdd4a6d74bb180a8859206e1452f5aa1 35 | Shared IPv4/6 address functions 36 | Introduce TLS-2 Key metadata "source IP" filter 37 | Commit 343652d89f9bc6a7cf3d4bdd927102a2b6db778c 38 | IPv4/6 Client source IP matching 39 | Introduce new Level Security setting for client-connect 40 | Commit 41e4699a2ef14ffc1998ded92f6d445da5fcb027 41 | Help to transition clients to TLS-Crypt-V2 keys 42 | Introduce TLS-Crypt-V2 Group Keys 43 | Commit 9d165c9da585a6535c18dfddec7db12ee8cab50e 44 | Commit e43542d95be12c5752d26158e34620bccb3eb25b 45 | This allows Groups of users to use the same key 46 | Remove STALE_FILE TIMEOUT for TLS-Crypt-V2 metadata storage 47 | Commit f0a9ae75f9500699fb57d9439988260d419381de 48 | Use stacking or blocking instead, by configuration var 49 | Add support for Openvpn dynamic client-connect file 50 | Commit c89cdff35362feb4d7e01e64d74c94983bbc92be 51 | This alows Openvpn server to push dynamic options 52 | Allow multiple Custom_Groups per server 53 | Commit 3c857413200cac30ea1f7b4fa951374e7bfc5424 54 | This allows clients to be sub-divided by Custom_Group 55 | Abandon easytls-verify.sh 56 | Commit 682ba0ff48535f0575cc220be3717f89281f986d 57 | Script is no longer required due to UV_TLSKEY_SERIAL 58 | Add UV_TLSKEY_SERIAL to be pushed to server 59 | Commit 5ccdb9f37a94ec92d7447afbcf08db7264a55213 60 | All clients using TLS-Crypt-V2 keys must push the 61 | TLS-Key serial number to identify the key 62 | Removed option --openvpn 63 | Commit cf413bd199c2b611314e895e8c9d1be30a02fd12 64 | Development only requirement 65 | Introduce vars files for server side scripts 66 | Commit 12dcd3f3078be8266d194e1d0b90db716aec0f82 67 | The command line was too long when run under Windows 68 | due to the extra requirement of loading sh.exe 69 | 70 | Version 2.5 71 | * 2021-08-13 - Commit c0ace6c6740315407776bef1b3b6a4827be36f84 72 | Introduce `easytls-conn-trac.lib` 73 | Commit a05e4f1ab003be3fbc63f5f00ec2d546c80cc4ab 74 | Add TLS-Crypt-V2 connection tracking 75 | Commit cca482808521807b5b72203dfcc4ea170615c817 76 | conn-trac is disabled by default 77 | Introduce `easytls-client-disconnect.sh` and `vars` file 78 | Commit 4172a08c79182b2b091b3c1fa31eca59551afe11 79 | Required by conn-trac (Disabled by default) 80 | Add Server authentication script vars files 81 | Commit 611758b18a092fc3d2dfc1d31d6d1ebb2393392b 82 | Allows parameters to be change with restarting server 83 | Introduce `remove-metadata` 84 | Commit b243aae45e70448d22c244cfe643f6a73956d37b 85 | Allows selective removal of `# metadata` records from client inline files. 86 | Introduce intermediate TLS-key security levels in client connect 87 | Commit 8a4a9987c51d797adef35f76a4b60b8e07d14e38 88 | Allow clients to seamlessly transition to TLS-Crypt-V2 keys. 89 | Add new hwaddr format 90 | Commit d27ffc93d39c48e9dc58e362e273ff5f678f266f 91 | Makes for cleaner regexpr 92 | Disable inline-index for No-CA mode 93 | Commit d44c0f09d84f5480aa45df9784ef25f78c4b7bbf 94 | Allows inline files to be manually edited (Fingerprint) 95 | Make No-CA mode completely independent of Easy-RSA 96 | Commit fd8fa84b9733c5816db3ec889db4b20b2856d718 97 | Introduce fingerprint sharing function 98 | Commit 1fb4b3d46a5907d3c18fa67f3abf4fb5f7558acc 99 | Allows fingerprints to be automatically inlined 100 | 101 | Version 2.4 102 | * 2021-07-21 - Commit 8160cbc42e377e6fa34b819359e718e75e2a5560 103 | Add self-signed certificates to inter-active `build` menu 104 | Commit 8160cbc42e377e6fa34b819359e718e75e2a5560 105 | 106 | Version 2.3 107 | * 2021-07-20 - Commit 939ba157ac113fcbb8d11e2dcfc76f8aaadb689b 108 | Add kill-client option 109 | Commit 51af501989b1185a9af5b12e705488a599daad93 110 | Change HWADDR field format (Maintain old format compat) 111 | Commit 9dd07b90260c64a39b32eba75a98c37e25427dfd 112 | 113 | Version 2.2 114 | * 2021-06-15 - Commit 32ccb2d52ad6c9cbd66a869c744f0c159ff88dc1 115 | Move to libera.chat IRC 116 | Commit 32ccb2d52ad6c9cbd66a869c744f0c159ff88dc1 117 | Complete overhaul of easytls-verify.sh 118 | Commit 3df16cf70d6ed7ae785b5fc7cfdb9f128aee5a50 119 | Easy-TLS now fully supports 'no-ca' mode. 120 | This is a complete replacement of Easy-RSA. 121 | Complete script support for --tls-auth and --tls-crypt keys 122 | Commit 1dab7536cce344c931861bdb75c76f7c06333ed6 123 | Add build self signed server/client certificates 124 | Commit 8f78129c73af47ed0aa87dfa4272c28771baf5c7 125 | Allow addition/deletion of arbitrary config labels 126 | Commit 237dab2ad5e3a68fe010cc8b2c0dfb7d9acab1ee 127 | Renamed cmd opt 'nokey' to 'no-key' 128 | Commit 5dc17aee11c44b31a433d09dc7f4b99e99e9ae38 129 | 130 | Version 2.1 131 | * 2021-05-23 - Commit 234ced916c9e7e6f3e5bf9205c87a84528d62ad2 132 | Introduce 'no-ca' mode to support OpenVPN Peer-Fingerprint mode 133 | Commit 234ced916c9e7e6f3e5bf9205c87a84528d62ad2 134 | 135 | Version 1.28 136 | * No tag 137 | Add an X509 style check for certificate revocation to --tls-verify 138 | Commit 38af6f4d23ed4f5eb7afc2356dc42f826af9a35b 139 | Introduce support for --tls-auth and --tls-crypt(v1) clients 140 | Commit 4815f858d5af82696ff908cb09f8cbc86a5d022a 141 | 142 | Version 1.27 (First official release) 143 | * 2021-03-31 - Commit cd52aede5447df145528ca961b832fcb81d2d5ea 144 | 145 | Creation date 146 | * 2020-03-13 - Commit c25717ca613fae34f1b9bce68127846628ef4ec5 147 | 148 | -------------------------------------------------------------------------------- /doc/easytls-details.txt: -------------------------------------------------------------------------------- 1 | ________ ________ ________ ___ ___ ________ ___ ________ 2 | / ______/\ / ____ _/\ /_______/\ / _/\/ _/\ /___ ___/\ / _/\ /_______/\ 3 | //\\____\/ //\\_//\\///\\____\\/ //\\_//\\/____ \\_//\\_\/ //\\/ //\\____\\/ 4 | /____/\ /____ / / /______ /\ /_ __/ / /___/\ // / // / /______ /\ 5 | _//\\__\/ _//\\_// / _\\____// / \/ /\\\/ \\__\/_//_/ _ //_/__ _\\____// / 6 | /_______/\ /__/\/__/\ / ______/ / /___/\ /___/\ /_______/\ /_______/ / 7 | \\______\/ \\_\/\\_\/ \\______\/ \\__\/ \\__\/ \\______\/ \\______\/ 8 | 9 | < (C) Richard T Bonhomme 2020 > 10 | 11 | Easy-TLS in detail 12 | 13 | The main focus of Easy-TLS is to provide an easy way to manage OpenVPN 14 | and EasyRSA assorted certificates and keys into fully verified 'inline' 15 | files which can be used immediately. 16 | 17 | The second focus of Easy-TLS is to provide TLS-Crypt-V2 key metadata 18 | which conforms to the original format as described by syzzer. 19 | 20 | * For full details see: 21 | https://github.com/OpenVPN/openvpn/blob/master/doc/tls-crypt-v2.txt 22 | (syzzer's work) 23 | 24 | The third focus is to provide server side scripts to interogate the 25 | TLS-crypt-v2 metadata and provide options to manage client connections. 26 | All this can be done prior to exposing x509 code. 27 | 28 | * OpenVPN '--tls-crypt-v2' keys and '--tls-crypt-v2-verify' script. 29 | 30 | These are new keys and a new script hook for OpenVPN. 31 | 32 | * Usage: 33 | 34 | To use the 'easytls' script simply copy it to the same directory that 35 | you have installed easyrsa in. 36 | 37 | Easy-TLS comes with full inter-active menus which make usage very easy. 38 | Use: 39 | * `./easytls build` - Build keys 40 | * `./easytls inline` - Inline all required files per node 41 | * `./easytls remove` - Remove keys and inline files in order 42 | * `./easytls script` - Configure server side scripts 43 | 44 | For full help use: 45 | * ./easytls -h 46 | * ./easytls-cryptv2-verify.sh -h 47 | * ./easytls-client-connect.sh -h 48 | * ./easytls-client-disconnect.sh -h 49 | 50 | Easy-TLS No-CA Mode 51 | 52 | Easy-TLS also has a No-CA mode, which does not require an Easy-RSA CA. 53 | Easy-TLS can build self-signed certificates and keys for use with OpenVPN. 54 | Easy-TLS can automatically share fingerprins among peer inline files. 55 | 56 | To use this mode: 57 | * `./easytsa init-tls no-ca` 58 | * `./easytls selfsign` - Inter-active menu to build self-signed certificates. 59 | * `./easytls self-sign-server ` 60 | * `./easytls self-sign-client ` 61 | 62 | 63 | TLS-Crypt-v2 client key metadata details: 64 | 65 | * This metadata field is constructed as follows: 66 | 67 | 1. Four part field. 68 | 69 | TLS-Crypt-V2 key serial number. (SHA256 or SHA1) 70 | EG: 4504cc7595f802344e7200c11fc1586f06fe18d546e8343abbe2b53ee1edfa90 71 | 72 | A 32bit random padding string. EG: 4d76a07e 73 | 74 | Easy-TLS identifier string: 'easytls' 75 | 76 | EasyTLS metadata version string: "$EASYTLS_VERSION". EG: 1.27 77 | 78 | Example: 79 | 4504cc7595f802344e7200c11fc1586f06fe18d546e8343abbe2b53ee1edfa90-4d76a07e--easytls-1.27 80 | 81 | 2 Two part field. 82 | 83 | CA Fingerprint. (Formatted to one contiguous string, CA-Identity) 84 | EG: 2859809249AF76AADE8C585406380DF303A9C212AB91100A10D71B20319CA253 85 | 86 | Server X509 certificate CommonName. EG: s01 87 | 88 | Example: 89 | 2859809249AF76AADE8C585406380DF303A9C212AB91100A10D71B20319CA253-s01 90 | 91 | 3. Client X509 certificate serial-number. 92 | EG: 1607AD45763A27B447F67578C1B815F2 93 | 94 | 4. Creation-date. (date +%s - "Seconds since...") 95 | EG: 1617216408 96 | 97 | 5. User definable Custom-Group. 98 | This is a string which the user can use for identification: 99 | EG: "CompanyName" (One contiguous string) 100 | 101 | 6. Client X509 certificate CommonName. 102 | EG: c09 103 | 104 | 7. TLS-CryptV2 sub-key name. 105 | This allows clients to have an unlimited number of keys 106 | associated with their single X509 certificate. 107 | EG: Home 108 | 109 | 8. Unused field. 110 | 111 | 9. Hardware-address-list. 112 | EG: =EF1234567890=1234567890FE= 113 | 114 | 115 | EasyTLS verification scripts: 116 | 117 | * easytls-cryptv2-verify.sh (OpenVPN --tls-crypt-v2-verify) 118 | 119 | Verify TLS-Crypt-V2 key metadata: 120 | Key age, key serial number, key status (enabled/disabled), Custom-Group. 121 | Optional X509 certificate verification methods. (Details below) 122 | 123 | 124 | * Optional X509 certificate verification methods: 125 | 126 | 1. Verify via CRL --via-crl 127 | 128 | The CRL is searched for client serial number and the client 129 | connection is dropped if the client is found to be revoked. 130 | This is the default method and conforms to syzzers original 131 | specification. 132 | 133 | 2. Verify via CA --via-ca (Not enabled) 134 | 135 | The client serial number status is verified via OpenSSL CA. 136 | This method does not work because OpenSSL returns an inorrect 137 | status code. 138 | 139 | 3. Verify via openssl index.txt --via-index (Preferred) 140 | 141 | The client serial number status is verified via the OpenSSL 142 | index.txt file. 143 | 144 | Option --cache-id reads the CA Identity file from disk, 145 | instead of loading openssl to generate the CA fingerprint. 146 | 147 | Option --preload-cache-id="CA_ID" allows the server config to load 148 | the CA Identity from the command line as a parameter, eliminating 149 | the need to read the CA Identity file from disk, repeatedly. 150 | 151 | CA Identity is the openssl output for the CA fingerprint formatted 152 | to one contiguous string: 153 | 154 | * openssl fingerprint output: 'SHA256 Fingerprint=95:DC:42:...' 155 | * EasyTLS CA Identity format: '95DC42...' 156 | 157 | 158 | * easytls-client-connect.sh (OpenVPN --client-connect) 159 | 160 | Verify client hardware-address. 161 | Connection tracking. 162 | 163 | 164 | * easytls-client-disconnect.sh (OpenVPN --client-connect) 165 | 166 | Only used by connection tracking. 167 | 168 | 169 | Note about Server script exit codes: 170 | 171 | OpenVPN --log does not accept data from scripts under Windows 172 | so the exit codes are absolutely necessary to debug errors. 173 | -------------------------------------------------------------------------------- /doc/easytls-howto-ii.md: -------------------------------------------------------------------------------- 1 | # EasyTLS-Howto (By wiscii) 2 | 3 | ## Installation and usage instructions: 4 | 5 | ### Installation 6 | 7 | * Download [**`easytls`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls) to your EasyRSA3 working directory.
8 | `easytls` requires access to your PKI to verify and create keys.
9 | It is not necessary to have a separate directory for `easytls`
10 | 11 | * Download [**`easytls-cryptv2-verify.sh`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls-cryptv2-verify.sh)
12 | Requires access to the files created by `easytls`.
13 | 14 | * Download [**`easytls-client-connect.sh`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls-client-connect.sh)
15 | Requires access to temporary files created by `easytls-cryptv2-verify.sh`. (Client hardware address list)
16 | 17 | * Download [**`easytls-client-disconnect.sh`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls-client-disconnect.sh)
18 | Requires access to temporary files created by `easytls-client-connect.sh`. (conntrac list)
19 | 20 | * Download [**`easytls-conntrac.lib`**](https://github.com/TinCanTech/easy-tls/blob/master/easytls-conntrac.lib)
21 | Required by `easytls-client-connect.sh` and `easytls-client-disconnect.sh`.
22 | 23 | ### Getting Started 24 | * **Please use the help:** 25 | ``` 26 | ./easytls help - General help 27 | ./easytls help - Command help 28 | ./easytls help options - Command --options 29 | ./easytls help abb - Command abbreviations 30 | ./easytls help config - Configuration help 31 | ``` 32 | * **Use inter-active menus:** 33 | ``` 34 | ./easytls build - Build keys 35 | ./easytls inline - Create Inline files 36 | ./easytls remove - Remove Inline files and keys 37 | ./easytls script - Configure server side scripts 38 | ``` 39 | These inter-active menus will take you through all the options for building TLS keys
40 | and inlining all the required files for a credentials only OpenVPN inline configuration file.
41 | 42 | ### EasyTLS Usage - Normal X509 mode 43 | 44 | First, you must have your EasyRSA-3 PKI fully setup, which includes CA, Server and Client certificates.
45 | * **Initialise:** 46 | ``` 47 | ./easytls init-tls 48 | ``` 49 | Default hash is SHA256 but Easy-TLS allows for use of SHA1
50 | Easy-TLS optional use of SHA1 is not considered to be a security risk.
51 |
52 | This will also create your CA-Identity file and `ca.id` configuration record.
53 |
54 | * **Status:** 55 | ``` 56 | ./easytls status 57 | ``` 58 | * **Check your configuration:** 59 | ``` 60 | ./easytls config 61 | ``` 62 | This is a good time to set your `custom.group`.
63 | You can use the `custom.group` option to save your Custom group, or use
64 | `--custom-group=XYZ` on the command line for all the commands which need it.
65 |
66 | * **Build keys and inline files**
67 | Use the inter-active menus above. 68 | 69 | ### EasyTLS Usage - No-CA mode 70 | 71 | No-CA mode means you do not require Easy-RSA to build your PKI.
72 | * **Initialise:** 73 | ``` 74 | ./easytls init-tls no-ca 75 | ``` 76 | You can now create Server and Client Self-signed certificates and keys.
77 |
78 | * **Use interactive menus:** 79 | ``` 80 | ./easytls self-sign - Build self-signed server/client certificates 81 | ``` 82 | Build your required certificates.
83 |
84 | Next, use the previous inter-active menus in the same way as before.
85 | 86 | ### Howto resolve issues with Invalid .inline files: 87 | 88 | If you receive a message informing you that you have "Revoked certs" or
89 | "Renewed certs" then simply use './easytls inline-remove '
90 | This will delete the offending Inline file and keep the EasyTLS index up-to-date.
91 | Invalid files are caused by x509 certificates which have been revoked.
92 | The Inline file is of no further value once the certificate has been revoked.
93 | 94 | 95 | -------------------------------------------------------------------------------- /easytls-client-connect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EASYTLS_VERSION="2.8.0" 4 | 5 | # Copyright - negotiable 6 | # 7 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 8 | # easytls-client-connect.sh -- Do simple magic 9 | # 10 | # Copyright (C) 2020 Richard Bonhomme (Friday 13th of March 2020) 11 | # https://github.com/TinCanTech/easy-tls 12 | # tincantech@protonmail.com 13 | # All Rights reserved. 14 | # 15 | # This code is released under version 2 of the GNU GPL 16 | # See LICENSE of this project for full licensing details. 17 | # 18 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 19 | # 20 | 21 | # Help 22 | help_text () 23 | { 24 | help_msg=" 25 | easytls-client-connect.sh 26 | 27 | This script is intended to be used by tls-crypt-v2 client keys 28 | generated by EasyTLS. See: https://github.com/TinCanTech/easy-tls 29 | 30 | Options: 31 | help|-h|--help This help text. 32 | -V|--version 33 | -v|--verbose Be a lot more verbose at run time (Not Windows). 34 | -s|--source-vars= 35 | Force Easy-TLS to source a vars file. 36 | The default vars file is sourced if no FILENAME is given. 37 | -a|--allow-no-check If the key has a hardware-address configured 38 | and the client did NOT use --push-peer-info 39 | then allow the connection. Otherwise, keys with a 40 | hardware-address MUST use --push-peer-info. 41 | -M|--ignore-x509-mismatch 42 | Ignore tlskey-x509 vs openvpn-x509 mismatch. 43 | -m|--ignore-hw-mismatch 44 | Ignore tlskey-hwaddr vs openvpn-hwaddr mismatch. 45 | -p|--push-required Require all clients to use --push-peer-info. 46 | -c|--crypt-v2-required Require all clients to use a TLS-Crypt-V2 key. 47 | -k|--key-hw-required Require all client keys to have a hardware-address. 48 | -i|--client-ip-match Match client source IP to Key metadata. 49 | -d|--dyn-opts= Path and name of Openvpn client dynamic options file. 50 | -w|--work-dir= Path to Easy-TLS scripts and vars for this server. 51 | -t|--tmp-dir= Temp directory where server-scripts write data. 52 | Default: *nix /tmp/easytls 53 | Windows C:/Windows/Temp/easytls 54 | -b|--base-dir= Path to OpenVPN base directory. (Windows Only) 55 | Default: C:/Progra~1/OpenVPN 56 | -o|--ovpnbin-dir= Path to OpenVPN bin directory. (Windows Only) 57 | Default: C:/Progra~1/OpenVPN/bin 58 | -e|--ersabin-dir= Path to Easy-RSA3 bin directory. (Windows Only) 59 | Default: C:/Progra~1/Openvpn/easy-rsa/bin 60 | 61 | Exit codes: 62 | 0 - Allow connection, Client hwaddr is correct or not required. 63 | 2 - Disallow connection, pushed hwaddr does not match. 64 | 3 - Disallow connection, hwaddr required and not pushed. 65 | 4 - Disallow connection, hwaddr required and not keyed. 66 | 5 - Disallow connection, Kill client. 67 | 6 - Disallow connection, TLS Auth/Crypt-v1 banned 68 | 7 - Disallow connection, X509 certificate incorrect for this TLS-key. 69 | 8 - Disallow connection, missing X509 client cert serial. (BUG) 70 | 9 - Disallow connection, unexpected failure. (BUG) 71 | 72 | 12 - Disallow connection, source IPaddr does not match. 73 | 74 | 18 - BUG Disallow connection, failed to read client_md_file_stack 75 | 19 - BUG Disallow connection, failed to parse metadata string 76 | 77 | 21 - USER ERROR Disallow connection, options error. 78 | 79 | 60 - USER ERROR Disallow connection, missing Temp dir 80 | 61 - USER ERROR Disallow connection, missing Base dir 81 | 62 - USER ERROR Disallow connection, missing Easy-RSA bin dir 82 | 63 - USER ERROR Disallow connection, missing Openvpn bin dir 83 | 64 - USER ERROR Disallow connection, missing openssl.exe 84 | 65 - USER ERROR Disallow connection, missing cat.exe 85 | 66 - USER ERROR Disallow connection, missing date.exe 86 | 67 - USER ERROR Disallow connection, missing grep.exe 87 | 68 - USER ERROR Disallow connection, missing sed.exe 88 | 69 - USER ERROR Disallow connection, missing printf.exe 89 | 70 - USER ERROR Disallow connection, missing rm.exe 90 | 71 - USER ERROR Disallow connection, missing metadata.lib 91 | 92 | 77 - BUG Disallow connection, failed to sources vars file 93 | 160 - BUG Disallow connection, stack error 94 | 253 - Disallow connection, exit code when --help is called. 95 | 254 - BUG Disallow connection, fail_and_exit() exited with default error code. 96 | 255 - BUG Disallow connection, die() exited with default error code. 97 | " 98 | print "${help_msg}" 99 | 100 | # For secrity, --help must exit with an error 101 | exit 253 102 | } 103 | 104 | # Wrapper around 'printf' - clobber 'print' since it's not POSIX anyway 105 | # shellcheck disable=SC1117 106 | print () { "${EASYTLS_PRINTF}" '%s\n' "${1}"; } 107 | verbose_print () 108 | { 109 | [ -n "${EASYTLS_VERBOSE}" ] || return 0 110 | print "${1}" 111 | print '' 112 | } 113 | banner () 114 | { 115 | [ -n "${EASYTLS_VERBOSE}" ] || return 0 116 | "${EASYTLS_PRINTF}" '\n%s\n\n' "${1}" 117 | } 118 | 119 | # Set the Easy-TLS version 120 | easytls_version () 121 | { 122 | verbose_print 123 | print "Easy-TLS version: ${EASYTLS_VERSION}" 124 | verbose_print 125 | } # => easytls_version () 126 | 127 | # Exit on error 128 | die () 129 | { 130 | # TLSKEY connect log 131 | tlskey_status "FATAL" || update_status "tlskey_status FATAL" 132 | 133 | easytls_version 134 | verbose_print " ${status_msg}" 135 | [ -z "${help_note}" ] || print "${help_note}" 136 | [ -z "${failure_msg}" ] || print "${failure_msg}" 137 | [ -z "${err_msg}" ] || print "${err_msg}" 138 | print "ERROR: ${1}" 139 | [ -z "${EASYTLS_FOR_WINDOWS}" ] || "${EASYTLS_PRINTF}" "%s\n%s\n" \ 140 | " ${status_msg}" "ERROR: ${1}" > "${EASYTLS_WLOG}" 141 | #exit "${2:-255}" 142 | if [ -n "${ENABLE_KILL_SERVER}" ]; then 143 | echo 1 > "${temp_stub}-die" 144 | echo 'XXXXX CC XXXXX KILL SERVER' 145 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 146 | "${EASYTLS_PRINTF}" "%s\n%s\n" \ 147 | " ${status_msg}" "ERROR: ${1}" > "${EASYTLS_WLOG}" 148 | taskkill /F /PID "${EASYTLS_srv_pid}" 149 | else 150 | kill -15 "${EASYTLS_srv_pid}" 151 | fi 152 | fi 153 | exit "${2:-255}" 154 | } # => die () 155 | 156 | # failure not an error 157 | fail_and_exit () 158 | { 159 | delete_metadata_files 160 | 161 | # stack_down does not errot to fail_and_exit, no need to remove lock 162 | #stack_down || die "stack_down - fail_and_exit" 163 | # Unlock 164 | #release_lock "${easytls_lock_stub}-stack.d" || \ 165 | # die "release_lock:stack FAIL" 99 166 | #update_status "stack-lock-released" 167 | 168 | print " ${status_msg}" 169 | print "${failure_msg}" 170 | print "${1} ${2}" 171 | 172 | # TLSKEY connect log 173 | tlskey_status "!*! FAIL" || update_status "tlskey_status FAIL" 174 | 175 | [ -z "${EASYTLS_FOR_WINDOWS}" ] || "${EASYTLS_PRINTF}" "%s\n%s\n" \ 176 | " ${status_msg}" "${failure_msg}" "${1} ${2}" > "${EASYTLS_WLOG}" 177 | exit "${2:-254}" 178 | } # => fail_and_exit () 179 | 180 | # Delete all metadata files 181 | delete_metadata_files () 182 | { 183 | # shellcheck disable=SC2154 # auth_control_file 184 | "${EASYTLS_RM}" -f "${EASYTLS_KILL_FILE}" 185 | 186 | # stack_down takes care of "${client_md_file_stack}" 187 | 188 | update_status "temp-files deleted" 189 | } # => delete_metadata_files () 190 | 191 | # Log fatal warnings 192 | warn_die () 193 | { 194 | if [ -n "${1}" ]; then 195 | fatal_msg="${fatal_msg} 196 | ${1}" 197 | else 198 | [ -z "${fatal_msg}" ] || die "${fatal_msg}" 21 199 | fi 200 | } # => warn_die () 201 | 202 | # Update status message 203 | update_status () 204 | { 205 | status_msg="${status_msg} => ${*}" 206 | } # => update_status () 207 | 208 | # Remove colons ':' and up-case 209 | format_number () 210 | { 211 | "${EASYTLS_PRINTF}" '%s' "${1}" | \ 212 | "${EASYTLS_SED}" -e 's/://g' -e 'y/abcdef/ABCDEF/' 213 | } # => format_number () 214 | 215 | #=# 9273398a-5284-4c1f-aec5-d597ceb1d085 216 | 217 | # Verbose message 218 | verbose_easytls_tctip_lib () 219 | { 220 | [ -z "${EASYTLS_SILENT}" ] || return 0 221 | [ -n "${EASYTLS_TCTIP_LIB_VERBOSE}" ] || return 0 222 | "${EASYTLS_PRINTF}" '%s\n' "${1}" 223 | } # => verbose_easytls_tctip_lib () 224 | 225 | # Front end validate IP address 226 | validate_ip_address () 227 | { 228 | [ "${1}" = "${1%%.*}" ] || ipv4=1 229 | [ "${1}" = "${1%%:*}" ] || ipv6=1 230 | [ -n "${ipv4}${ipv6}" ] || return 1 231 | if [ -n "${ipv4}" ] && [ -n "${ipv6}" ]; then 232 | easytls_verbose "Unsupported <:Port>" 233 | return 1 234 | fi 235 | [ -n "${ipv4}" ] && validate_ip4_data "$@" && valid4=1 236 | [ -n "${ipv6}" ] && validate_ip6_data "$@" && valid6=1 237 | [ -n "${valid4}" ] && [ -n "${valid6}" ] && return 1 238 | [ -z "${valid4}" ] && [ -z "${valid6}" ] && return 1 239 | } # => validate_ip_address () 240 | 241 | # Exit with error 242 | invalid_address () 243 | { 244 | case "${1}" in 245 | 1) print "easytls invalid" ;; 246 | 10) print "excess input" ;; 247 | 11) print "illegal format" ;; 248 | 12) print "illegal mask" ;; 249 | 13) print "mask range" ;; 250 | 14) print "leading zero" ;; 251 | 15) print "class range" ;; 252 | 16) print "class count" ;; 253 | 17) print "cidr mask" ;; 254 | 18) print "input error" ;; 255 | 19) print "ip2dec error" ;; 256 | 20) 257 | print "ip6/mask-length mismatch" 258 | print "ip6/mask correct example: 1:22:333:4444:5::/80" 259 | ;; 260 | *) print "undocumented ${1} ?" ;; 261 | esac 262 | } # => invalid_address () 263 | 264 | # IPv4 address to decimal 265 | ip2dec () 266 | { 267 | case "${1}" in 268 | *[!1234567890.]* | .* | *. | *..* ) return 1 ;; 269 | *.*.*.* ) : ;; #OK 270 | * ) return 1 ;; 271 | esac 272 | 273 | temp_ip_addr="${1}" 274 | a="${temp_ip_addr%%.*}"; temp_ip_addr="${temp_ip_addr#*.}" 275 | b="${temp_ip_addr%%.*}"; temp_ip_addr="${temp_ip_addr#*.}" 276 | c="${temp_ip_addr%%.*}"; temp_ip_addr="${temp_ip_addr#*.}" 277 | d="${temp_ip_addr%%.*}" 278 | 279 | for i in "${a}" "${b}" "${c}" "${d}"; do 280 | [ "${#i}" -gt 1 ] || continue 281 | [ -n "${i%%0*}" ] || return 1 282 | if [ 0 -gt "${i}" ] || [ "${i}" -gt 255 ]; then return 1; fi 283 | done 284 | ip4_dec="$(( (a << 24) + (b << 16) + (c << 8) + d ))" || return 1 285 | unset -v temp_ip_addr a b c d 286 | } # => ip2dec () 287 | 288 | # IPv4 CIDR mask length to decimal 289 | cidrmask2dec () 290 | { 291 | mask_dec=0 292 | imsk_dec=0 293 | count=32 # or 128 - If possible.. 294 | power=1 295 | while [ "${count}" -gt 0 ]; do 296 | count="$(( count - 1 ))" 297 | if [ "${1}" -gt "${count}" ]; then 298 | # mask 299 | mask_dec="$(( mask_dec + power ))" 300 | else 301 | # inverse 302 | imsk_dec="$(( imsk_dec + power ))" 303 | fi 304 | power="$(( power * 2 ))" 305 | done 306 | unset -v count power 307 | } # => cidrmask2dec () 308 | 309 | # EXPAND IPv6 310 | expand_ip6_address () 311 | { 312 | [ -z "${2}" ] || return 10 313 | in_ip_addr="${1}" 314 | shift 315 | 316 | in_valid_hextets="${in_ip_addr%/*}" 317 | in_valid_mask_len="${in_ip_addr##*/}" 318 | unset -v in_ip_addr 319 | 320 | # mask length 321 | case "${in_valid_mask_len}" in 322 | "${in_valid_hextets}" | '' ) in_valid_mask_len=128 ;; 323 | [!1234567890] | 0* ) return 11 ;; 324 | * ) : # OK 325 | esac 326 | if [ 0 -gt "${in_valid_mask_len}" ] || [ "${in_valid_mask_len}" -gt 128 ] 327 | then 328 | return 11 329 | fi 330 | 331 | # ADDRESS 6 332 | temp_valid_hextets="${in_valid_hextets}" 333 | 334 | # expand leading colon 335 | [ "${temp_valid_hextets}" = "${temp_valid_hextets#:}" ] || \ 336 | lead_colon=1 337 | [ -z "${lead_colon}" ] || temp_valid_hextets="0${temp_valid_hextets}" 338 | 339 | # Count valid compressed hextets 340 | count_valid_hextets=0 341 | while [ -n "${temp_valid_hextets}" ]; do 342 | count_valid_hextets="$(( count_valid_hextets + 1 ))" 343 | if [ "${temp_valid_hextets}" = "${temp_valid_hextets#*:}" ]; then 344 | temp_valid_hextets="${temp_valid_hextets}:" 345 | fi 346 | temp_valid_hextets="${temp_valid_hextets#*:}" 347 | temp_valid_hextets="${temp_valid_hextets#:}" 348 | done 349 | verbose_easytls_tctip_lib "count_valid_hextets: ${count_valid_hextets}" 350 | 351 | # expand double colon 352 | temp_valid_hextets="${in_valid_hextets}" 353 | expa_valid_hextets="${in_valid_hextets}" 354 | if [ "${count_valid_hextets}" -lt 8 ]; then 355 | hi_part="${temp_valid_hextets%::*}" 356 | lo_part="${temp_valid_hextets#*::}" 357 | missing_zeros="$(( 8 - count_valid_hextets ))" 358 | while [ "${missing_zeros}" -gt 0 ]; do 359 | hi_part="${hi_part}:0" 360 | missing_zeros="$(( missing_zeros - 1 ))" 361 | done 362 | unset -v missing_zeros 363 | expa_valid_hextets="${hi_part}:${lo_part}" 364 | # Re-expand leading colon 365 | [ -z "${lead_colon}" ] || expa_valid_hextets="0${expa_valid_hextets}" 366 | fi 367 | # Save the orangutan 368 | unset -v lead_colon lo_part hi_part count_valid_hextets 369 | verbose_easytls_tctip_lib "expa_valid_hextets: ${expa_valid_hextets}" 370 | 371 | temp_valid_hextets="${expa_valid_hextets}" 372 | hex_count=8 373 | unset -v full_valid_hextets delim 374 | # Expand compressed zeros 375 | while [ "${hex_count}" -gt 0 ]; do 376 | hextet="${temp_valid_hextets%%:*}" 377 | while [ "${#hextet}" -lt 4 ]; do 378 | hextet="0${hextet}" 379 | done 380 | full_valid_hextets="${full_valid_hextets}${delim}${hextet}" 381 | delim=':' 382 | temp_valid_hextets="${temp_valid_hextets#*:}" 383 | hex_count="$(( hex_count - 1 ))" 384 | done 385 | # Save "The violence inherent in the system" 386 | unset -v hex_count delim 387 | verbose_easytls_tctip_lib "full_valid_hextets: ${full_valid_hextets}" 388 | 389 | # Split IP at mask_len 390 | [ "$(( in_valid_mask_len % 4 ))" -eq 0 ] || \ 391 | die "in_valid_mask_len % 4: ${in_valid_mask_len}" 392 | hex_mask="$(( in_valid_mask_len / 4 ))" 393 | 394 | temp_valid_hextets="${full_valid_hextets}" 395 | while [ "${hex_mask}" -gt 0 ]; do 396 | delete_mask="${temp_valid_hextets#?}" 397 | verbose_easytls_tctip_lib "delete_mask: ${delete_mask}" 398 | hex_char="${temp_valid_hextets%"${delete_mask}"}" 399 | verbose_easytls_tctip_lib "hex_char: ${hex_char}" 400 | temp_valid_hextets="${temp_valid_hextets#?}" 401 | verbose_easytls_tctip_lib "temp_valid_hextets: ${temp_valid_hextets}" 402 | full_subnet_addr6="${full_subnet_addr6}${hex_char}" 403 | verbose_easytls_tctip_lib "full_subnet_addr6: ${full_subnet_addr6}" 404 | [ "${hex_char}" = ':' ] || hex_mask="$(( hex_mask - 1 ))" 405 | verbose_easytls_tctip_lib "*** hex_mask: ${hex_mask}" 406 | done 407 | # Save the polar ice-caps 408 | unset -v hex_char hex_mask delete_mask 409 | 410 | # The remainder should equal zero 411 | while [ -n "${temp_valid_hextets}" ]; do 412 | hextet="${temp_valid_hextets%%:*}" 413 | if [ -z "${hextet}" ]; then 414 | temp_valid_hextets="${temp_valid_hextets#*:}" 415 | hextet="${temp_valid_hextets%%:*}" 416 | fi 417 | 418 | if [ "${temp_valid_hextets}" = "${temp_valid_hextets#*:}" ]; then 419 | temp_valid_hextets="${temp_valid_hextets}:" 420 | fi 421 | temp_valid_hextets="${temp_valid_hextets#*:}" 422 | 423 | # shellcheck disable=SC2249 # (info): default *) case 424 | case "${hextet}" in 425 | *[!0:]* ) return 20 ;; 426 | esac 427 | done 428 | verbose_easytls_tctip_lib "full_valid_hextets: ${full_valid_hextets}" 429 | verbose_easytls_tctip_lib "full_subnet_addr6: ${full_subnet_addr6}" 430 | verbose_easytls_tctip_lib "temp_valid_hextets: ${temp_valid_hextets}" 431 | # Save the trees 432 | unset -v hextet temp_valid_hextets 433 | # Return full_valid_hextets full_subnet_addr6 434 | } # => expand_ip6_address () 435 | 436 | #=# b66633f8-3746-436a-901f-29638199b187 437 | 438 | # Allow connection 439 | connection_allowed () 440 | { 441 | absolute_fail=0 442 | update_status "connection allowed" 443 | } # => connection_allowed () 444 | 445 | # Update conntrac 446 | update_conntrac () 447 | { 448 | # Source conntrac lib 449 | lib_file="${EASYTLS_WORK_DIR}/easytls-conntrac.lib" 450 | [ -f "${lib_file}" ] || \ 451 | lib_file="${EASYTLS_WORK_DIR}/dev/easytls-conntrac.lib" 452 | # shellcheck source=./easytls-conntrac.lib 453 | if [ -f "${lib_file}" ]; then 454 | . "${lib_file}" || die "Source failed: ${lib_file}" 77 455 | unset -v lib_file 456 | else 457 | die "Missing file: ${lib_file}" 77 458 | fi 459 | 460 | # Absolute start time 461 | easytls_start_d_file="${EASYTLS_CONN_TRAC}-start-d" 462 | if [ ! -f "${easytls_start_d_file}" ]; then 463 | # shellcheck disable=SC2154 # daemon_start_time 464 | "${EASYTLS_PRINTF}" '%s' \ 465 | "${daemon_start_time}" > "${easytls_start_d_file}" 466 | fi 467 | # shellcheck disable=SC2034 468 | easytls_start_d="$("$EASYTLS_CAT" "${easytls_start_d_file}")" 469 | 470 | # Begin conntrac_record 471 | conntrac_record="${UV_TLSKEY_SERIAL:-TLSAC}=${client_serial}" 472 | conntrac_record="${conntrac_record}==${common_name}" 473 | 474 | # Detect IP Pool exhausted 475 | # shellcheck disable=SC2154 476 | if [ -z "${ifconfig_pool_remote_ip}" ]; then 477 | # Kill the server 478 | [ -z "${POOL_EXHAUST_FATAL}" ] || { 479 | ENABLE_KILL_SERVER=1 480 | die "IP_POOL_EXHASTED" 101 481 | } 482 | 483 | # Otherwise, the client will connect but get no IP 484 | ip_pool_exhausted=1 485 | conntrac_record="${conntrac_record}==0.0.0.0" 486 | banner "********* WARNING: IP POOL EXHAUSTED *********" 487 | 488 | # This will kill the client 489 | [ -z "${POOL_EXHAUST_KILL_CLIENT}" ] || { 490 | "${EASYTLS_CAT}" "${EASYTLS_DYN_OPTS_FILE}" 491 | "${EASYTLS_PRINTF}" '%s\n' "disable" 492 | } > "${ovpn_dyn_opts_file}" 493 | else 494 | conntrac_record="${conntrac_record}==${ifconfig_pool_remote_ip}" 495 | fi 496 | 497 | # shellcheck disable=SC2154 498 | [ -z "${peer_id}" ] || conntrac_record="${conntrac_record}==${peer_id}" 499 | 500 | # shellcheck disable=SC2154 501 | timestamp="${local_date_ascii}=${local_time_ascii}" 502 | 503 | conntrac_record="${conntrac_record}==${timestamp}" 504 | # shellcheck disable=SC2154 505 | conntrac_record="${conntrac_record}++${untrusted_ip}:${untrusted_port}" 506 | 507 | conn_trac_connect "${conntrac_record}" "${EASYTLS_CONN_TRAC}" || { 508 | case "$?" in 509 | 6) # Duplicate TLSKEY 510 | update_status "conn_trac_connect DUPLICATE_TLSKEY" 511 | conntrac_dupl=1 512 | ;; 513 | 2) # Duplicate record, includes VPN-IP 0.0.0.0 (Pool exhausted) 514 | update_status "conn_trac_connect FAIL" 515 | conntrac_fail=1 516 | ;; 517 | 1) # Fatal because these are usage errors 518 | update_status "conn_trac_connect ERROR" 519 | conntrac_error=1 520 | ;; 521 | 9) # Absolutely fatal 522 | ENABLE_KILL_SERVER=1 523 | die "CONNTRAC_CONNECT_CT_LOCK_9" 96 524 | ;; 525 | *) # Absolutely fatal 526 | conntrac_unknown=1 527 | ;; 528 | esac 529 | } 530 | 531 | # Log failure 532 | if [ -n "${conntrac_dupl}" ] || [ -n "${conntrac_fail}" ] || \ 533 | [ -n "${conntrac_error}" ] ||[ -n "${conntrac_unknown}" ] 534 | then 535 | if [ -n "${ENABLE_CONNTRAC_FAIL_LOG}" ]; then 536 | { 537 | [ ! -f "${EASYTLS_CONN_TRAC}.fail" ] || \ 538 | "${EASYTLS_CAT}" "${EASYTLS_CONN_TRAC}.fail" 539 | "${EASYTLS_PRINTF}" '%s ' "${timestamp}" 540 | [ -z "${conntrac_fail}" ] || \ 541 | "${EASYTLS_PRINTF}" '%s ' "Pre-Reg" 542 | [ -z "${conntrac_error}" ] || \ 543 | "${EASYTLS_PRINTF}" '%s ' "ERROR" 544 | [ -z "${ip_pool_exhausted}" ] || \ 545 | "${EASYTLS_PRINTF}" '%s ' "IP-POOL" 546 | [ -z "${conntrac_dupl}" ] || \ 547 | "${EASYTLS_PRINTF}" '%s ' "DUPL-TLSK" 548 | [ -z "${conntrac_unknown}" ] || \ 549 | "${EASYTLS_PRINTF}" '%s ' "UNKNOWN!" 550 | "${EASYTLS_PRINTF}" '%s\n' "CON: ${conntrac_record}" 551 | } > "${EASYTLS_CONN_TRAC}.fail.tmp" || die "conn: conntrac file" 156 552 | "${EASYTLS_MV}" "${EASYTLS_CONN_TRAC}.fail.tmp" \ 553 | "${EASYTLS_CONN_TRAC}.fail" || die "conn: conntrac file" 157 554 | fi # ENABLE_CONNTRAC_FAIL_LOG 555 | 556 | # Absolutely fatal 557 | [ -z "${conntrac_unknown}" ] || { 558 | ENABLE_KILL_SERVER=1 559 | die "CONNTRAC_CONNECT_UNKNOWN" 98 560 | } 561 | 562 | # # Fatal because these are usage errors 563 | if [ -n "${conntrac_error}" ] && [ -n "${FATAL_CONN_TRAC}" ]; then 564 | ENABLE_KILL_SERVER=1 565 | die "CONNTRAC_CONNECT_ERROR" 99 566 | fi 567 | 568 | # Duplicate record, includes VPN-IP 0.0.0.0 (Pool exhausted) 569 | if [ -n "${conntrac_fail}" ] && [ -n "${FATAL_CONN_TRAC_2}" ]; then 570 | ENABLE_KILL_SERVER=1 571 | die "CONNTRAC_CONNECT_FAIL_2" 91 572 | fi 573 | 574 | # Duplicate TLS keys 575 | if [ -n "${conntrac_dupl}" ]; then 576 | [ -z "${ENFORCE_UNIQUE_TLSKEY}" ] || \ 577 | fail_and_exit "Duplicate TLS Key" 578 | update_status "IGNORE Duplicate TLS Key" 579 | fi 580 | fi 581 | unset -v env_file conntrac_record conntrac_fail conntrac_error 582 | } # => update_contrac () 583 | 584 | # Stack down 585 | stack_down () 586 | { 587 | [ -z "${stack_completed}" ] || die "STACK_DOWN CAN ONLY RUN ONCE" 161 588 | stack_completed=1 589 | 590 | # file exists or the client pushed an incorrect UV_TLSKEY_SERIAL 591 | [ -f "${client_md_file_stack}" ] || return 0 592 | 593 | # Lock 594 | acquire_lock "${easytls_lock_stub}-stack.d" || \ 595 | die "acquire_lock:stack FAIL" 99 596 | update_status "stack-lock-acquired" 597 | 598 | unset -v stack_err 599 | i=0 600 | s='' 601 | 602 | # Full Stack DOWN 603 | while : 604 | do 605 | i="$(( i + 1 ))" 606 | if [ -f "${client_md_file_stack}_${i}" ]; then 607 | [ "${i}" -eq 1 ] || s="${s}." 608 | else 609 | if [ "${i}" -eq 1 ]; then 610 | # There are no stacked files so delete the original 611 | [ -f "${client_md_file_stack}" ] || die "***" 163 612 | "${EASYTLS_RM}" "${client_md_file_stack}" || stack_err=1 613 | update_status "stack-down: clear" 614 | tlskey_status " | = stack: clear -" 615 | else 616 | # Delete the last file found 617 | p="$(( i - 1 ))" 618 | [ -f "${client_md_file_stack}_${p}" ] || die "_i***" 164 619 | "${EASYTLS_RM}" "${client_md_file_stack}_${p}" || stack_err=1 620 | update_status "stack-down: ${p}" 621 | tlskey_status " | <= stack:- ${s}${p} -" 622 | fi 623 | break 624 | fi 625 | done 626 | 627 | # Unlock 628 | release_lock "${easytls_lock_stub}-stack.d" || \ 629 | die "release_lock:stack FAIL" 99 630 | update_status "stack-lock-released" 631 | 632 | [ -z "${stack_err}" ] || die "STACK_DOWN_FULL_ERROR" 160 633 | } # => stack_down () 634 | 635 | # TLSKEY tracking .. because .. 636 | tlskey_status () 637 | { 638 | # >> may fail on easytls/github/actions/wtest - No TERM 639 | [ -n "${EASYTLS_TLSKEY_STATUS}" ] || return 0 640 | { 641 | # shellcheck disable=SC2154 642 | "${EASYTLS_PRINTF}" '%s %s %s %s\n' "${local_date_ascii}" \ 643 | "${UV_TLSKEY_SERIAL:-TLSAC}" "CONN:${1}" \ 644 | "${common_name} ${UV_REAL_NAME}" 645 | } >> "${EASYTLS_TK_XLOG}" 646 | } # => tlskey_status () 647 | 648 | # Retry pause 649 | retry_pause () 650 | { 651 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 652 | ping -n 1 127.0.0.1 653 | else 654 | sleep 1 655 | fi 656 | } # => retry_pause () 657 | 658 | # Simple lock dir 659 | acquire_lock () 660 | { 661 | [ -n "${1}" ] || return 1 662 | unset -v lock_acquired 663 | lock_attempt="${LOCK_TIMEOUT}" 664 | set -o noclobber 665 | while [ "${lock_attempt}" -gt 0 ]; do 666 | [ "${lock_attempt}" -eq "${LOCK_TIMEOUT}" ] || retry_pause 667 | lock_attempt="$(( lock_attempt - 1 ))" 668 | "${EASYTLS_MKDIR}" "${1}" || continue 669 | lock_acquired=1 670 | break 671 | done 672 | set +o noclobber 673 | [ -n "${lock_acquired}" ] || return 1 674 | } # => acquire_lock () 675 | 676 | # Release lock 677 | release_lock () 678 | { 679 | [ -d "${1}" ] || return 0 680 | "${EASYTLS_RM}" -r "${1}" 681 | } # => release_lock () 682 | 683 | # easytls-metadata.lib 684 | #=# 35579017-b084-4d6b-94d5-76397c2d4a1f 685 | 686 | # Break metadata_string into variables 687 | # shellcheck disable=SC2034 # foo appears unused. Verify it or export it. 688 | metadata_string_to_vars () 689 | { 690 | MD_TLSKEY_SERIAL="${1%%-*}" || return 1 691 | 692 | #seed="${*}" || return 1 693 | #MD_SEED="${seed#*-}" || return 1 694 | #unset -v seed 695 | 696 | #md_padding="${md_seed%%--*}" || return 1 697 | md_easytls_ver="${1#*--}" || return 1 698 | MD_EASYTLS="${md_easytls_ver%-*}" || return 1 699 | unset -v md_easytls_ver 700 | 701 | MD_IDENTITY="${2%%-*}" || return 1 702 | MD_SRV_NAME="${2##*-}" || return 1 703 | MD_x509_SERIAL="${3}" || return 1 704 | MD_DATE="${4}" || return 1 705 | MD_CUSTOM_G="${5}" || return 1 706 | MD_NAME="${6}" || return 1 707 | MD_SUBKEY="${7}" || return 1 708 | MD_OPT="${8}" || return 1 709 | MD_FILTERS="${9}" || return 1 710 | } # => metadata_string_to_vars () 711 | 712 | # Break metadata string at delimeter: New Newline, old space 713 | # shellcheck disable=SC2034 # foo appears unused. Verify it or export it. 714 | metadata_stov_safe () 715 | { 716 | [ -n "$1" ] || return 1 717 | input="$1" 718 | 719 | # Not using IFS 720 | err_msg="Unspecified delimiter" 721 | delim_save="${delimiter}" 722 | delimiter="${delimiter:-${newline}}" 723 | [ -n "${delimiter}" ] || return 1 724 | case "${input}" in 725 | *"${delimiter}"*) : ;; 726 | *) delimiter=' ' 727 | esac 728 | 729 | MD_SEED="${input#*-}" 730 | 731 | # Expansions inside ${..} need to be quoted separately, 732 | # otherwise they will match as a pattern. 733 | # Which is the required behaviour. 734 | # shellcheck disable=SC2295 735 | { # Required group for shellcheck 736 | m1="${input%%${delimiter}*}" 737 | input="${input#*${delimiter}}" 738 | m2="${input%%${delimiter}*}" 739 | input="${input#*${delimiter}}" 740 | m3="${input%%${delimiter}*}" 741 | input="${input#*${delimiter}}" 742 | m4="${input%%${delimiter}*}" 743 | input="${input#*${delimiter}}" 744 | m5="${input%%${delimiter}*}" 745 | input="${input#*${delimiter}}" 746 | m6="${input%%${delimiter}*}" 747 | input="${input#*${delimiter}}" 748 | m7="${input%%${delimiter}*}" 749 | input="${input#*${delimiter}}" 750 | m8="${input%%${delimiter}*}" 751 | input="${input#*${delimiter}}" 752 | m9="${input%%${delimiter}*}" 753 | input="${input#*${delimiter}}" 754 | } 755 | 756 | # An extra space has been used, probably in the name 757 | err_msg="metadata-lib: ${m9} vs ${input}" 758 | [ "${m9}" = "${input}" ] || return 1 759 | 760 | delimiter="${delim_save}" 761 | 762 | err_msg="metadata-lib: metadata_string_to_vars" 763 | metadata_string_to_vars "$m1" "$m2" "$m3" "$m4" \ 764 | "$m5" "$m6" "$m7" "$m8" "$m9" || return 1 765 | unset -v m1 m2 m3 m4 m5 m6 m7 m8 m9 input err_msg 766 | } # => metadata_stov_safe () 767 | 768 | #=# 70b4ec32-f1fc-47fb-a261-f02e7f572b62 769 | 770 | # Initialise 771 | init () 772 | { 773 | # Fail by design 774 | absolute_fail=1 775 | delimiter=' 776 | ' 777 | 778 | # Defaults 779 | if [ -z "${EASYTLS_UNIT_TEST}" ]; then 780 | EASYTLS_srv_pid="${PPID}" 781 | else 782 | EASYTLS_srv_pid=999 783 | fi 784 | 785 | # Log message 786 | status_msg="* EasyTLS-client-connect" 787 | 788 | # Identify Windows 789 | # shellcheck disable=SC2016 790 | EASYRSA_KSH='@(#)MIRBSD KSH R39-w32-beta14 $Date: 2013/06/28 21:28:57 $' 791 | # shellcheck disable=SC2154 792 | if [ "${KSH_VERSION}" = "${EASYRSA_KSH}" ]; then 793 | EASYTLS_FOR_WINDOWS=1 794 | fi 795 | 796 | # Required binaries 797 | EASYTLS_OPENSSL='openssl' 798 | EASYTLS_CAT='cat' 799 | EASYTLS_DATE='date' 800 | EASYTLS_GREP='grep' 801 | EASYTLS_MKDIR='mkdir' 802 | EASYTLS_MV='mv' 803 | EASYTLS_SED='sed' 804 | EASYTLS_PRINTF='printf' 805 | EASYTLS_RM='rm' 806 | 807 | # Directories and files 808 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 809 | # Windows 810 | host_drv="${PATH%%\:*}" 811 | base_dir="${EASYTLS_base_dir:-${host_drv}:/Progra~1/Openvpn}" 812 | EASYTLS_ersabin_dir="${EASYTLS_ersabin_dir:-${base_dir}/easy-rsa/bin}" 813 | EASYTLS_ovpnbin_dir="${EASYTLS_ovpnbin_dir:-${base_dir}/bin}" 814 | 815 | [ -d "${base_dir}" ] || exit 61 816 | [ -d "${EASYTLS_ersabin_dir}" ] || exit 62 817 | [ -d "${EASYTLS_ovpnbin_dir}" ] || exit 63 818 | [ -f "${EASYTLS_ovpnbin_dir}/${EASYTLS_OPENSSL}.exe" ] || exit 64 819 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_CAT}.exe" ] || exit 65 820 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_DATE}.exe" ] || exit 66 821 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_GREP}.exe" ] || exit 67 822 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_MKDIR}.exe" ] || exit 72 823 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_MV}.exe" ] || exit 71 824 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_SED}.exe" ] || exit 68 825 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_PRINTF}.exe" ] || exit 69 826 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_RM}.exe" ] || exit 70 827 | 828 | export PATH="${EASYTLS_ersabin_dir};${EASYTLS_ovpnbin_dir};${PATH}" 829 | fi 830 | } # => init () 831 | 832 | # Dependancies 833 | deps () 834 | { 835 | # Source vars file 836 | prog_dir="${0%/*}" 837 | EASYTLS_WORK_DIR="${EASYTLS_WORK_DIR:-${prog_dir}}" 838 | default_vars="${EASYTLS_WORK_DIR}/easytls-client-connect.vars" 839 | EASYTLS_VARS_FILE="${EASYTLS_VARS_FILE:-${default_vars}}" 840 | if [ -f "${EASYTLS_VARS_FILE}" ]; then 841 | # .vars-example is correct for shellcheck 842 | # shellcheck source=examples/easytls-client-connect.vars-example 843 | . "${EASYTLS_VARS_FILE}" || die "Source failed: ${EASYTLS_VARS_FILE}" 77 844 | update_status "vars loaded" 845 | else 846 | [ -z "${EASYTLS_REQUIRE_VARS}" ] || \ 847 | die "Missing file: ${EASYTLS_VARS_FILE}" 77 848 | fi 849 | 850 | # Source metadata lib 851 | lib_file="${EASYTLS_WORK_DIR}/easytls-metadata.lib" 852 | [ -f "${lib_file}" ] || \ 853 | lib_file="${EASYTLS_WORK_DIR}/dev/easytls-metadata.lib" 854 | if [ -f "${lib_file}" ]; then 855 | # shellcheck source=dev/easytls-metadata.lib 856 | . "${lib_file}" || die "Failed to source: ${lib_file}" 857 | easytls_metadata_lib_ver 858 | fi 859 | 860 | # Source tctip lib 861 | lib_file="${EASYTLS_WORK_DIR}/easytls-tctip.lib" 862 | [ -f "${lib_file}" ] || \ 863 | lib_file="${EASYTLS_WORK_DIR}/dev/easytls-tctip.lib" 864 | if [ -f "${lib_file}" ]; then 865 | # shellcheck source=dev/easytls-tctip.lib 866 | . "${lib_file}" || die "Failed to source: ${lib_file}" 867 | easytls_tctip_lib_ver 868 | fi 869 | 870 | unset -v default_vars EASYTLS_VARS_FILE EASYTLS_REQUIRE_VARS prog_dir lib_file 871 | 872 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 873 | WIN_TEMP="${host_drv}:/Windows/Temp" 874 | export EASYTLS_tmp_dir="${EASYTLS_tmp_dir:-${WIN_TEMP}}" 875 | else 876 | export EASYTLS_tmp_dir="${EASYTLS_tmp_dir:-/tmp}" 877 | fi 878 | 879 | # Test temp dir 880 | [ -d "${EASYTLS_tmp_dir}" ] || exit 60 881 | 882 | # Temp files name stub 883 | temp_stub="${EASYTLS_tmp_dir}/easytls-${EASYTLS_srv_pid}" 884 | 885 | # Lock dir 886 | easytls_lock_stub="${temp_stub}-lock" 887 | LOCK_TIMEOUT="${LOCK_TIMEOUT:-30}" 888 | 889 | # Need the date/time .. 890 | #full_date="$("${EASYTLS_DATE}" '+%s %Y/%m/%d-%H:%M:%S')" 891 | # shellcheck disable=SC2154 892 | full_date="${time_ascii}" 893 | local_date_ascii="${full_date% *}" 894 | local_time_ascii="${full_date#* }" 895 | 896 | # Windows log 897 | EASYTLS_WLOG="${temp_stub}-client-connect.log" 898 | EASYTLS_TK_XLOG="${temp_stub}-tcv2-ct.x-log" 899 | 900 | # Conn track 901 | EASYTLS_CONN_TRAC="${temp_stub}-conn-trac" 902 | 903 | # Kill server file 904 | if [ -f "${temp_stub}-die" ]; then 905 | print "Kill Server Signal -> exit CC" 906 | exit 9 907 | fi 908 | 909 | # Kill client file 910 | EASYTLS_KILL_FILE="${temp_stub}-kill-client" 911 | 912 | # Dynamic opts file 913 | if [ -f "${EASYTLS_DYN_OPTS_FILE}" ] && [ -n "${ovpn_dyn_opts_file}" ] 914 | then 915 | "${EASYTLS_CAT}" "${EASYTLS_DYN_OPTS_FILE}" > "${ovpn_dyn_opts_file}" 916 | update_status "dyn opts loaded" 917 | fi 918 | 919 | } 920 | 921 | ####################################### 922 | 923 | # Initialise 924 | init 925 | 926 | # Options 927 | while [ -n "${1}" ]; do 928 | # Separate option from value: 929 | opt="${1%%=*}" 930 | val="${1#*=}" 931 | empty_ok="" # Empty values are not allowed unless expected 932 | 933 | case "${opt}" in 934 | help|-h|--help) 935 | empty_ok=1 936 | help_text 937 | ;; 938 | -V|--version) 939 | easytls_version 940 | exit 9 941 | ;; 942 | -v|--verbose) 943 | empty_ok=1 944 | EASYTLS_VERBOSE=1 945 | ;; 946 | -s|--source-vars) 947 | empty_ok=1 948 | EASYTLS_REQUIRE_VARS=1 949 | case "${val}" in 950 | -s|--source-vars) 951 | unset -v EASYTLS_VARS_FILE ;; 952 | *) 953 | EASYTLS_VARS_FILE="${val}" ;; 954 | esac 955 | ;; 956 | -a|--allow-no-check) 957 | empty_ok=1 958 | ENABLE_NO_CHECK=1 959 | ;; 960 | -m|--ignore-hw-mismatch) # tlskey-hwaddr does not match openvpn-hwaddr 961 | empty_ok=1 962 | IGNORE_HWADDR_MISMATCH=1 963 | ;; 964 | -M|--ignore-x509-mismatch) # tlskey-x509 does not match openvpn-x509 965 | empty_ok=1 966 | IGNORE_X509_MISMATCH=1 967 | ;; 968 | -p|--push-hwaddr-required) 969 | empty_ok=1 970 | ENFORCE_PUSH_HWADDR=1 971 | ;; 972 | -c|--crypt-v2-required) 973 | empty_ok=1 974 | ENFORCE_CRYPT_V2=1 975 | ;; 976 | -k|--key-hwaddr-required) 977 | empty_ok=1 978 | ENFORCE_KEY_HWADDR=1 979 | ;; 980 | -i|--client-ip-match) 981 | empty_ok=1 982 | PEER_IP_MATCH=1 983 | ;; 984 | -d|--dyn-opts) 985 | EASYTLS_DYN_OPTS_FILE="${val}" 986 | [ -f "${EASYTLS_DYN_OPTS_FILE}" ] || \ 987 | warn_die "Easy-TLS dynamic opts file missing" 988 | ;; 989 | -w|--work-dir) 990 | EASYTLS_WORK_DIR="${val}" 991 | ;; 992 | -t|--tmp-dir) 993 | EASYTLS_tmp_dir="${val}" 994 | ;; 995 | -b|--base-dir) 996 | EASYTLS_base_dir="${val}" 997 | ;; 998 | -o|--openvpn-bin-dir) 999 | EASYTLS_ovpnbin_dir="${val}" 1000 | ;; 1001 | -e|--easyrsa-bin-dir) 1002 | EASYTLS_ersabin_dir="${val}" 1003 | ;; 1004 | *) 1005 | empty_ok=1 1006 | if [ -f "${opt}" ]; then 1007 | # Do not need this in the log but keep it here for reference 1008 | #[ -z "${EASYTLS_VERBOSE}" ] || echo "Ignoring temp file: $opt" 1009 | ovpn_dyn_opts_file="${opt}" 1010 | else 1011 | warn_die "Unknown option: ${opt}" 1012 | fi 1013 | ;; 1014 | esac 1015 | 1016 | # fatal error when no value was provided 1017 | if [ -z "${empty_ok}" ] && { [ "${val}" = "${1}" ] || [ -z "${val}" ]; } 1018 | then 1019 | warn_die "Missing value to option: ${opt}" 1020 | fi 1021 | shift 1022 | done 1023 | 1024 | # Report and die on fatal warnings 1025 | warn_die 1026 | 1027 | # Dependencies 1028 | deps 1029 | 1030 | # Write env file 1031 | if [ -n "${WRITE_ENV}" ]; then 1032 | env_file="${temp_stub}-client-connect.env" 1033 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 1034 | set > "${env_file}" 1035 | else 1036 | env > "${env_file}" 1037 | fi 1038 | unset -v env_file WRITE_ENV 1039 | fi 1040 | 1041 | # Update log message 1042 | # shellcheck disable=SC2154 # common_name 1043 | [ -n "${common_name}" ] || die "Missing common_name" 150 1044 | update_status "CN: ${common_name}" 1045 | 1046 | # Set Client certificate serial number from Openvpn env 1047 | # shellcheck disable=SC2154 1048 | client_serial="$(format_number "${tls_serial_hex_0}")" 1049 | 1050 | # Verify Client certificate serial number 1051 | [ -n "${client_serial}" ] || die "Missing client_serial" 8 1052 | 1053 | # conntrac connect 1054 | if [ -n "${ENABLE_CONN_TRAC}" ]; then 1055 | update_conntrac || die "update_conntrac FAIL" 170 1056 | else 1057 | #update_status "conn-trac disabled" 1058 | : 1059 | fi 1060 | 1061 | # Check for kill signal 1062 | if [ -f "${EASYTLS_KILL_FILE}" ] && \ 1063 | "${EASYTLS_GREP}" -q "${client_serial}" "${EASYTLS_KILL_FILE}" 1064 | then 1065 | # Kill client 1066 | kill_this_client=1 1067 | update_status "Kill client signal" 1068 | fi 1069 | 1070 | # Cannot verify UV_TLSKEY_SERIAL yet 1071 | 1072 | # Fixed file for TLS-CV2 1073 | if [ -n "${UV_TLSKEY_SERIAL}" ]; then 1074 | client_md_file_stack="${temp_stub}-tcv2-metadata-${UV_TLSKEY_SERIAL}" 1075 | update_status "tls key serial: ${UV_TLSKEY_SERIAL}" 1076 | 1077 | if [ -f "${client_md_file_stack}" ]; then 1078 | # Get client metadata_string 1079 | metadata_string="$("${EASYTLS_CAT}" "${client_md_file_stack}")" 1080 | [ -n "${metadata_string}" ] || \ 1081 | fail_and_exit "failed to read client_md_file_stack" 18 1082 | 1083 | # Convert metadata string to variables 1084 | metadata_stov_safe "$metadata_string" || \ 1085 | die "client_metadata_string_to_vars" 151 1086 | 1087 | [ -n "${MD_TLSKEY_SERIAL}" ] || \ 1088 | fail_and_exit "failed to set MD_TLSKEY_SERIAL" 19 1089 | unset -v metadata_string 1090 | update_status "client_md_file_stack loaded" 1091 | 1092 | # shellcheck disable=SC2154 1093 | if [ "${MD_x509_SERIAL}" = "${client_serial}" ]; then 1094 | update_status "metadata -> x509 serial match" 1095 | 1096 | elif [ "${MD_x509_SERIAL}" = '00000000000000000000000000000000' ]; then 1097 | # Client could still push a fake UV_TLSKEY_SERIAL 1098 | # is only vulnerable if many clients use the same GROUP key 1099 | # client must still have valid X509 keys and certs 1100 | update_status "metadata -> GROUP key" 1101 | else 1102 | # Client pushed UV_TLSKEY_SERIAL which does not match X509 1103 | # Should NOT be allowed - Client has copied another key 1104 | [ -n "${IGNORE_X509_MISMATCH}" ] || { 1105 | failure_msg="TLS-key is being used by the wrong client certificate" 1106 | fail_and_exit "TLSKEY_X509_SERIAL-OVPN_X509_SERIAL-MISMATCH*1" 6 1107 | } 1108 | update_status "IGNORE metadata -> x509 serial mismatch" 1109 | fi 1110 | 1111 | else 1112 | # Client pushed an incorrect UV_TLSKEY_SERIAL 1113 | # Should NOT be allowed - Client has copied another UV_TLSKEY_SERIAL only 1114 | [ -z "${ENFORCE_TLSKEY_SERIAL_MATCH}" ] || { 1115 | failure_msg="PUSHED UV_TLSKEY_SERIAL ${UV_TLSKEY_SERIAL}" 1116 | fail_and_exit "INCORRECT UV_TLSKEY_SERIAL PUSHED" 1117 | } 1118 | update_status "IGNORE incorrect UV_TLSKEY_SERIAL" 1119 | fi 1120 | # Clear one stack now - client_md_file_stack is no longer required 1121 | stack_down || die "stack_down FAIL" 165 1122 | else 1123 | # This is correct behaviour for --tls-auth/crypt v1 1124 | update_status "CLIENT FAILED TO PUSH UV_TLSKEY_SERIAL" 1125 | no_uv_tlskey_serial=1 1126 | # Require crypt-v2 1127 | [ -z "${ENFORCE_CRYPT_V2}" ] || { 1128 | failure_msg="TLS Auth/Crypt key not allowed" 1129 | fail_and_exit "TLS_CRYPT_V2 ONLY" 6 1130 | } 1131 | update_status "IGNORE TLS-Auth/Crypt-v1 only" 1132 | fi 1133 | 1134 | # Set hwaddr from Openvpn env 1135 | # This is not a dep. different clients may not push-peer-info 1136 | # shellcheck disable=SC2154 # IV_HWADDR 1137 | push_hwaddr="$(format_number "${IV_HWADDR}")" 1138 | if [ -z "${push_hwaddr}" ]; then 1139 | push_hwaddr_missing=1 1140 | update_status "hwaddr not pushed" 1141 | fi 1142 | 1143 | # This test being here allows to force all clients to use push-peer-info 1144 | # May need the same for IP addresses 1145 | if [ -n "${push_hwaddr_missing}" ]; then 1146 | # hwaddr is NOT pushed 1147 | [ -z "${ENFORCE_PUSH_HWADDR}" ] || { 1148 | failure_msg="Client did not push required hwaddr" 1149 | fail_and_exit "PUSHED HWADDR REQUIRED BUT NOT PUSHED" 3 1150 | } 1151 | # hwaddr not pushed and not required 1152 | update_status "IGNORE hwaddr not required" 1153 | fi 1154 | 1155 | # ENABLE_NO_CHECK 1156 | if [ -n "${ENABLE_NO_CHECK}" ]; then 1157 | # disable all checks 1158 | update_status "Allow ALL TLS keys" 1159 | connection_allowed 1160 | else 1161 | # Check for TLS Auth/Crypt 1162 | if [ -n "${no_uv_tlskey_serial}" ]; then 1163 | # TLS Auth/Crypt 1164 | update_status "TLS Auth/Crypt key only" 1165 | if [ -n "${ENFORCE_PUSH_HWADDR}" ] && [ -n "${push_hwaddr_missing}" ] 1166 | then 1167 | failure_msg="TLS Auth/Crypt no pushed hwaddr" 1168 | fail_and_exit "PUSHED HWADDR REQUIRED BUT NOT PUSHED" 3 1169 | fi 1170 | 1171 | [ -z "${ENFORCE_CRYPT_V2}" ] || { 1172 | failure_msg="TLS Auth/Crypt key not allowed" 1173 | fail_and_exit "TLS_CRYPT_V2 ONLY" 6 1174 | } 1175 | [ -z "${ENFORCE_KEY_HWADDR}" ] || { 1176 | failure_msg="TLS Auth/Crypt key enforce verify hwaddr" 1177 | fail_and_exit "TLS_CRYPT_V2 ONLY " 6 1178 | } 1179 | # TLS Auth/Crypt-v1 allowed here 1180 | connection_allowed 1181 | else 1182 | # TLS-Crypt-V2 1183 | 1184 | # Set only for NO keyed hwaddr 1185 | # shellcheck disable=SC2154 1186 | if [ "${MD_FILTERS}" = '=000000000000=' ] || \ 1187 | [ "${MD_FILTERS}" = '+000000000000+' ] 1188 | then 1189 | key_hwaddr_missing=1 1190 | fi 1191 | 1192 | # IP address check 1193 | if [ -n "${PEER_IP_MATCH}" ]; then 1194 | # First: Check metadata for IP addresses 1195 | # If no IP in metadata then cannot perform test, so ignore 1196 | 1197 | # Extract and sort 4/6 IP addresses from metadata 1198 | unset -v found_ipv6 key_ip6_list found_ipv4 key_ip4_list \ 1199 | source_match delim4 delim6 1200 | key_ip_list="${MD_FILTERS%=}" 1201 | until [ -z "${key_ip_list}" ]; do 1202 | # hw_addr = the last hwaddr in the list 1203 | key_ip_addr="${key_ip_list##*=}" 1204 | # Drop the last hwaddr 1205 | key_ip_list="${key_ip_list%=*}" 1206 | 1207 | # IPv6 key list 1208 | if [ "${key_ip_addr}" = "${key_ip_addr##*:}" ]; then 1209 | # Not IPv6 Ignore 1210 | : 1211 | else 1212 | found_ipv6=1 1213 | key_ip6_list="${key_ip6_list}${delim6}${key_ip_addr}" 1214 | delim6=' ' 1215 | fi 1216 | 1217 | # IPv4 key list 1218 | if [ "${key_ip_addr}" = "${key_ip_addr##*.}" ]; then 1219 | # Not IPv4 Ignore 1220 | : 1221 | else 1222 | found_ipv4=1 1223 | key_ip4_list="${key_ip4_list}${delim4}${key_ip_addr}" 1224 | delim4=' ' 1225 | fi 1226 | done 1227 | unset -v delim4 delim6 1228 | 1229 | # shellcheck disable=SC2154 1230 | if [ -n "${found_ipv6}" ] && [ -n "${trusted_ip6}" ]; then 1231 | unset -v peer_ip6_match_ok 1232 | # Test 1233 | peer_ip6_addr="${trusted_ip6}/128" 1234 | until [ -z "${key_ip6_list}" ]; do 1235 | key_ip_addr="${key_ip6_list% *}" 1236 | key_ip6_addr="${key_ip_addr%%/*}" 1237 | 1238 | # bits is no longer saved to key for IPv6 1239 | #key_ip6_bits="${key_ip_addr##*/}" 1240 | 1241 | expand_ip6_address "${peer_ip6_addr}" 1242 | exp_peer_ip6_addr="${full_valid_hextets}" 1243 | 1244 | case "${exp_peer_ip6_addr}" in 1245 | "${key_ip6_addr}"* ) peer_ip_match_ok=1 ;; 1246 | * ) unset -v peer_ip_match_ok ;; 1247 | esac 1248 | # Save Pandas 1249 | unset -v key_ip_addr key_ip6_addr key_ip6_bits \ 1250 | exp_peer_ip6_addr 1251 | 1252 | # Discard lead hextet 1253 | key_ip6_list="${key_ip6_list#* }" 1254 | if [ "${key_ip6_list}" = "${key_ip6_list#* }" ]; then 1255 | key_ip6_list="${key_ip6_list##*}" 1256 | fi 1257 | done 1258 | unset -v key_ip6_list peer_ip6_addr 1259 | 1260 | else 1261 | # Ignore 1262 | : 1263 | fi 1264 | 1265 | # shellcheck disable=SC2154 1266 | if [ -n "${found_ipv4}" ] && [ -n "${trusted_ip}" ]; then 1267 | # Set IP addr from Openvpn env 1268 | peer_ip4_addr="${trusted_ip}" 1269 | # Test 1270 | ip2dec "${peer_ip4_addr}" 1271 | peer_ip4_addr_dec="${ip4_dec}" 1272 | unset -v ip4_dec peer_ip4_match_ok 1273 | until [ -z "${key_ip4_list}" ]; do 1274 | key_ip_addr="${key_ip4_list% *}" 1275 | key_ip4_addr="${key_ip_addr%%/*}" 1276 | ip2dec "${key_ip4_addr}" 1277 | key_ip4_addr_dec="${ip4_dec}" 1278 | 1279 | key_ip4_bits="${key_ip_addr##*/}" 1280 | cidrmask2dec "${key_ip4_bits}" 1281 | key_ip4_mask_dec="${mask_dec}" 1282 | #key_ip4_imsk_dec="${imsk_dec}" 1283 | unset -v mask_dec imsk_dec ip4_dec 1284 | 1285 | # Binary 1286 | key_and4_mask_dec=$(( key_ip4_addr_dec & key_ip4_mask_dec )) 1287 | peer_and4_mask_dec=$(( peer_ip4_addr_dec & key_ip4_mask_dec )) 1288 | if [ "${key_and4_mask_dec}" -eq "${peer_and4_mask_dec}" ] 1289 | then 1290 | # v4 Match! 1291 | peer_ip_match_ok=1 1292 | fi 1293 | # Save the rain forest 1294 | unset -v key_ip_addr key_ip4_addr key_ip4_addr_dec key_ip4_bits \ 1295 | key_ip4_mask_dec key_and4_mask_dec peer_and4_mask_dec 1296 | 1297 | # Decapitate 1298 | key_ip4_list="${key_ip4_list#* }" 1299 | if [ "${key_ip4_list}" = "${key_ip4_list#* }" ]; then 1300 | key_ip4_list="${key_ip4_list##*}" 1301 | fi 1302 | done 1303 | else 1304 | # Ignore 1305 | : 1306 | fi 1307 | 1308 | if [ -n "${found_ipv6}" ] || [ -n "${found_ipv4}" ]; then 1309 | # matadata has an address and this test is enabled so .. 1310 | [ -n "${peer_ip_match_ok}" ] || \ 1311 | fail_and_exit "SOURCE_IP_MISMATCH!" 12 1312 | update_status "IP Matched!" 1313 | else 1314 | # No IP-addr found in metadata then key not locked to IP 1315 | update_status "No Key IPaddr IGNORED!" 1316 | #no_key_ip_addr=1 1317 | fi 1318 | # Save the deep blue sea 1319 | unset -v found_ipv6 found_ipv4 source_match key_ip_list key_ip_addr 1320 | fi 1321 | 1322 | # Verify hwaddr 1323 | # hwaddr is pushed 1324 | if [ -n "${key_hwaddr_missing}" ]; then 1325 | # key does not have a hwaddr 1326 | update_status "Key is not locked to hwaddr" 1327 | [ -z "${ENFORCE_KEY_HWADDR}" ] || { 1328 | failure_msg="Key hwaddr required but missing" 1329 | fail_and_exit "KEYED HWADDR REQUIRED BUT NOT KEYED" 4 1330 | } 1331 | # No keyed hwaddr and TLS-crypt-v2 1332 | connection_allowed 1333 | else 1334 | #[ -f "${client_md_file_stack}" ] || \ 1335 | # die "CC Missing client_md_file_stack" 1336 | 1337 | hw_list="${MD_FILTERS%=}" 1338 | until [ -z "${hw_list}" ]; do 1339 | # hw_addr = the last hwaddr in the list 1340 | hw_addr="${hw_list##*=}" 1341 | # Drop the last hwaddr 1342 | hw_list="${hw_list%=*}" 1343 | 1344 | if [ "${push_hwaddr}" = "${hw_addr}" ]; then 1345 | # push and MATCH! 1346 | push_and_match=1 1347 | break 1348 | fi 1349 | done 1350 | 1351 | if [ -n "${push_and_match}" ]; then 1352 | update_status "hwaddr ${push_hwaddr} pushed and matched" 1353 | connection_allowed 1354 | else 1355 | # push does not match key hwaddr 1356 | if [ -n "${IGNORE_HWADDR_MISMATCH}" ]; then 1357 | connection_allowed 1358 | update_status "IGNORE hwaddr mismatch!" 1359 | else 1360 | failure_msg="hwaddr mismatch - pushed: ${push_hwaddr}" 1361 | fail_and_exit "HWADDR MISMATCH" 2 1362 | fi 1363 | fi 1364 | fi 1365 | fi 1366 | fi # ENABLE_NO_CHECK 1367 | 1368 | # Any failure_msg means fail_and_exit 1369 | [ -z "${failure_msg}" ] || fail_and_exit "NEIN: ${failure_msg}" 9 1370 | 1371 | # For DUBUG 1372 | if [ -n "${FORCE_ABSOLUTE_FAIL}" ]; then 1373 | absolute_fail=1 1374 | failure_msg="FORCE_ABSOLUTE_FAIL" 1375 | fi 1376 | 1377 | # Collect kill signal 1378 | [ -z "${kill_this_client}" ] || fail_and_exit "KILL_CLIENT_SIGNAL" 5 1379 | 1380 | # There is only one way out of this... 1381 | if [ "${absolute_fail}" -eq 0 ]; then 1382 | # Delete all temp files 1383 | delete_metadata_files || die "CON: delete_metadata_files() ?" 155 1384 | 1385 | # TLSKEY connect log 1386 | tlskey_status " >>++> C-OK" || update_status "tlskey_status FAIL" 1387 | 1388 | # All is well 1389 | verbose_print "${local_date_ascii} ${status_msg}" 1390 | [ -z "${EASYTLS_FOR_WINDOWS}" ] || "${EASYTLS_PRINTF}" "%s\n" \ 1391 | "${status_msg}" > "${EASYTLS_WLOG}" 1392 | exit 0 1393 | fi 1394 | 1395 | # Otherwise 1396 | fail_and_exit "ABSOLUTE FAIL" 9 1397 | -------------------------------------------------------------------------------- /easytls-client-disconnect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EASYTLS_VERSION="2.8.0" 4 | 5 | # Copyright - negotiable 6 | # 7 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 8 | # easytls-client-disconnect.sh -- Do simple magic 9 | # 10 | # Copyright (C) 2020 Richard Bonhomme (Friday 13th of March 2020) 11 | # https://github.com/TinCanTech/easy-tls 12 | # tincantech@protonmail.com 13 | # All Rights reserved. 14 | # 15 | # This code is released under version 2 of the GNU GPL 16 | # See LICENSE of this project for full licensing details. 17 | # 18 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 19 | # 20 | 21 | # Help 22 | help_text () 23 | { 24 | help_msg=" 25 | easytls-client-disconnect.sh 26 | 27 | This script is intended to be used by tls-crypt-v2 client keys 28 | generated by EasyTLS. See: https://github.com/TinCanTech/easy-tls 29 | 30 | Options: 31 | help|-h|--help This help text. 32 | -V|--version 33 | -v|--verbose Be a lot more verbose at run time (Not Windows). 34 | -s|--source-vars= 35 | Force Easy-TLS to source a vars file. 36 | The default vars file is sourced if no FILENAME is given. 37 | -w|--work-dir= Path to Easy-TLS scripts and vars for this server. 38 | -t|--tmp-dir= Temp directory where server-scripts write data. 39 | Default: *nix /tmp/easytls 40 | Windows C:/Windows/Temp/easytls 41 | -b|--base-dir= Path to OpenVPN base directory. (Windows Only) 42 | Default: C:/Progra~1/OpenVPN 43 | -o|--ovpnbin-dir= Path to OpenVPN bin directory. (Windows Only) 44 | Default: C:/Progra~1/OpenVPN/bin 45 | -e|--ersabin-dir= Path to Easy-RSA3 bin directory. (Windows Only) 46 | Default: C:/Progra~1/Openvpn/easy-rsa/bin 47 | 48 | Exit codes: 49 | 0 - Allow connection, Client hwaddr is correct or not required. 50 | 51 | 7 - Disallow connection, X509 certificate incorrect for this TLS-key. 52 | 8 - Disallow connection, missing X509 client cert serial. (BUG) 53 | 9 - Disallow connection, unexpected failure. (BUG) 54 | 55 | 18 - BUG Disallow connection, failed to read client_md_file_stack 56 | 19 - BUG Disallow connection, failed to parse metadata string 57 | 58 | 21 - USER ERROR Disallow connection, options error. 59 | 60 | 60 - USER ERROR Disallow connection, missing Temp dir 61 | 61 - USER ERROR Disallow connection, missing Base dir 62 | 62 - USER ERROR Disallow connection, missing Easy-RSA bin dir 63 | 63 - USER ERROR Disallow connection, missing Openvpn bin dir 64 | 64 - USER ERROR Disallow connection, missing openssl.exe 65 | 65 - USER ERROR Disallow connection, missing cat.exe 66 | 66 - USER ERROR Disallow connection, missing date.exe 67 | 67 - USER ERROR Disallow connection, missing grep.exe 68 | 68 - USER ERROR Disallow connection, missing sed.exe 69 | 69 - USER ERROR Disallow connection, missing printf.exe 70 | 70 - USER ERROR Disallow connection, missing rm.exe 71 | 71 - USER ERROR Disallow connection, missing metadata.lib 72 | 73 | 77 - BUG Disallow connection, failed to sources vars file 74 | 253 - Disallow connection, exit code when --help is called. 75 | 254 - BUG Disallow connection, fail_and_exit() exited with default error code. 76 | 255 - BUG Disallow connection, die() exited with default error code. 77 | " 78 | print "${help_msg}" 79 | 80 | # For secrity, --help must exit with an error 81 | exit 253 82 | } 83 | 84 | # Wrapper around 'printf' - clobber 'print' since it's not POSIX anyway 85 | # shellcheck disable=SC1117 86 | print () { "${EASYTLS_PRINTF}" "%s\n" "${1}"; } 87 | 88 | verbose_print () 89 | { 90 | [ -n "${EASYTLS_VERBOSE}" ] || return 0 91 | print "${1}" 92 | print "" 93 | } 94 | 95 | # Set the Easy-TLS version 96 | easytls_version () 97 | { 98 | verbose_print 99 | print "Easy-TLS version: ${EASYTLS_VERSION}" 100 | verbose_print 101 | } # => easytls_version () 102 | 103 | # Exit on error 104 | die () 105 | { 106 | # TLSKEY connect log 107 | tlskey_status "FATAL" || update_status "tlskey_status FATAL" 108 | 109 | easytls_version 110 | verbose_print " ${status_msg}" 111 | [ -z "${help_note}" ] || print "${help_note}" 112 | [ -z "${failure_msg}" ] || print "${failure_msg}" 113 | print "ERROR: ${1}" 114 | [ -z "${EASYTLS_FOR_WINDOWS}" ] || "${EASYTLS_PRINTF}" "%s\n%s\n" \ 115 | " ${status_msg}" "ERROR: ${1}" > "${EASYTLS_WLOG}" 116 | #exit "${2:-255}" 117 | if [ -n "${ENABLE_KILL_SERVER}" ]; then 118 | echo 1 > "${temp_stub}-die" 119 | echo 'XXXXX CD XXXXX KILL SERVER' 120 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 121 | "${EASYTLS_PRINTF}" "%s\n%s\n" \ 122 | " ${status_msg}" "ERROR: ${1}" > "${EASYTLS_WLOG}" 123 | taskkill /F /PID "${EASYTLS_srv_pid}" 124 | else 125 | kill -15 "${EASYTLS_srv_pid}" 126 | fi 127 | fi 128 | exit "${2:-255}" 129 | } # => die () 130 | 131 | # failure not an error 132 | fail_and_exit () 133 | { 134 | delete_metadata_files 135 | print " ${status_msg}" 136 | print "${failure_msg}" 137 | print "${1}" 138 | 139 | # TLSKEY connect log 140 | tlskey_status "!*! FAIL" || update_status "tlskey_status FAIL" 141 | 142 | [ -z "${EASYTLS_FOR_WINDOWS}" ] || "${EASYTLS_PRINTF}" "%s\n%s\n" \ 143 | " ${status_msg}" "${failure_msg}" "${1}" > "${EASYTLS_WLOG}" 144 | exit "${2:-254}" 145 | } # => fail_and_exit () 146 | 147 | # Delete all metadata files - Currently UNUSED 148 | delete_metadata_files () 149 | { 150 | "${EASYTLS_RM}" -f "${EASYTLS_KILL_FILE}" 151 | update_status "temp-files deleted" 152 | } # => delete_metadata_files () 153 | 154 | # Log fatal warnings 155 | warn_die () 156 | { 157 | if [ -n "${1}" ]; then 158 | fatal_msg="${fatal_msg} 159 | ${1}" 160 | else 161 | [ -z "${fatal_msg}" ] || die "${fatal_msg}" 21 162 | fi 163 | } # => warn_die () 164 | 165 | # Update status message 166 | update_status () 167 | { 168 | status_msg="${status_msg} => ${*}" 169 | } # => update_status () 170 | 171 | # Remove colons ':' and up-case 172 | format_number () 173 | { 174 | "${EASYTLS_PRINTF}" '%s' "${1}" | \ 175 | "${EASYTLS_SED}" -e 's/://g' -e 'y/abcdef/ABCDEF/' 176 | } # => format_number () 177 | 178 | # Allow disconnection 179 | disconnect_accepted () 180 | { 181 | absolute_fail=0 182 | update_status "disconnect completed" 183 | } # => disconnect_accepted () 184 | 185 | # Update conntrac 186 | update_conntrac () 187 | { 188 | # Source conntrac lib 189 | lib_file="${EASYTLS_WORK_DIR}/easytls-conntrac.lib" 190 | [ -f "${lib_file}" ] || \ 191 | lib_file="${EASYTLS_WORK_DIR}/dev/easytls-conntrac.lib" 192 | # shellcheck source=./easytls-conntrac.lib 193 | if [ -f "${lib_file}" ]; then 194 | . "${lib_file}" || die "Source failed: ${lib_file}" 77 195 | unset -v lib_file 196 | else 197 | die "Missing file: ${lib_file}" 77 198 | fi 199 | 200 | # Update connection tracking 201 | conntrac_record="${UV_TLSKEY_SERIAL:-TLSAC}" 202 | conntrac_record="${conntrac_record}=${client_serial}" 203 | # If common_name is not set then this is bug 160-2 204 | # Use username, which is still set, when common_name is lost 205 | # Set the username alternative first 206 | # shellcheck disable=SC2154 207 | conntrac_alt_rec="${conntrac_record}==${username}" 208 | # shellcheck disable=SC2154 209 | conntrac_alt2_rec="${conntrac_record}==${X509_0_CN}" 210 | # shellcheck disable=SC2154 211 | conntrac_record="${conntrac_record}==${common_name}" 212 | 213 | # shellcheck disable=SC2154 214 | if [ -z "${ifconfig_pool_remote_ip}" ]; then 215 | [ -z "${FATAL_CON_TRAC}" ] || fail_and_exit "IP_POOL_EXHASTED" 101 216 | ip_pool_exhausted=1 217 | conntrac_record="${conntrac_record}==0.0.0.0" 218 | conntrac_alt_rec="${conntrac_alt_rec}==0.0.0.0" 219 | conntrac_alt2_rec="${conntrac_alt2_rec}==0.0.0.0" 220 | else 221 | conntrac_record="${conntrac_record}==${ifconfig_pool_remote_ip}" 222 | conntrac_alt_rec="${conntrac_alt_rec}==${ifconfig_pool_remote_ip}" 223 | conntrac_alt2_rec="${conntrac_alt2_rec}==${ifconfig_pool_remote_ip}" 224 | fi 225 | 226 | # shellcheck disable=SC2154 227 | if [ -n "${peer_id}" ]; then 228 | conntrac_record="${conntrac_record}==${peer_id}" 229 | conntrac_alt_rec="${conntrac_alt_rec}==${peer_id}" 230 | conntrac_alt2_rec="${conntrac_alt2_rec}==${peer_id}" 231 | fi 232 | 233 | timestamp="${local_date_ascii}=${local_time_ascii}" 234 | conntrac_record="${conntrac_record}==${timestamp}" 235 | conntrac_alt_rec="${conntrac_alt_rec}==${timestamp}" 236 | conntrac_alt2_rec="${conntrac_alt2_rec}==${timestamp}" 237 | 238 | # shellcheck disable=SC2154 239 | conntrac_record="${conntrac_record}++${untrusted_ip}:${untrusted_port}" 240 | conntrac_alt_rec="${conntrac_alt_rec}++${untrusted_ip}:${untrusted_port}" 241 | conntrac_alt2_rec="${conntrac_alt2_rec}++${untrusted_ip}:${untrusted_port}" 242 | 243 | # Disconnect common_name 244 | conn_trac_disconnect "${conntrac_record}" "${EASYTLS_CONN_TRAC}" || { 245 | case "$?" in 246 | 3) # Missing conntrac file - Can happen if IP Pool exhausted 247 | [ -n "${ip_pool_exhausted}" ] || { 248 | ENABLE_KILL_SERVER=1 249 | die "CONNTRAC_DISCONNECT_FILE_MISSING" 97 250 | } 251 | # Ignore this error because it is expected 252 | update_status "IGNORE missing ct file due to IP POOL EXHAUSTED" 253 | ;; 254 | 2) # Not fatal because errors are expected #160 255 | update_status "conn_trac_disconnect FAIL" 256 | conntrac_fail=1 257 | log_env=1 258 | ;; 259 | 1) # Fatal because these are usage errors 260 | [ -z "${FATAL_CONN_TRAC}" ] || { 261 | ENABLE_KILL_SERVER=1 262 | die "CONNTRAC_DISCONNECT_FILE_ERROR" 99 263 | } 264 | update_status "conn_trac_disconnect ERROR" 265 | conntrac_error=1 266 | log_env=1 267 | ;; 268 | 9) # Absolutely fatal 269 | ENABLE_KILL_SERVER=1 270 | die "CONNTRAC_DISCONNECT_CT_LOCK_9.1" 96 271 | ;; 272 | *) # Absolutely fatal 273 | ENABLE_KILL_SERVER=1 274 | die "CONNTRAC_DISCONNECT_UNKNOWN" 98 275 | ;; 276 | esac 277 | } 278 | 279 | # If the first failed for number two then try again .. 280 | if [ -n "${conntrac_fail}" ]; then 281 | # Disconnect username 282 | conn_trac_disconnect "${conntrac_alt_rec}" "${EASYTLS_CONN_TRAC}" || { 283 | case "$?" in 284 | 2) # fatal later - because errors could happen #160 285 | update_status "conn_trac_disconnect A-FAIL" 286 | conntrac_alt_fail=1 287 | log_env=1 288 | ;; 289 | 1) # Fatal because these are usage errors 290 | [ -z "${FATAL_CONN_TRAC}" ] || { 291 | ENABLE_KILL_SERVER=1 292 | die "CONNTRAC_DISCONNECT_ALT_FILE_ERROR" 99 293 | } 294 | update_status "conn_trac_disconnect A-ERROR" 295 | conntrac_alt_error=1 296 | log_env=1 297 | ;; 298 | 9) # Absolutely fatal 299 | ENABLE_KILL_SERVER=1 300 | die "CONNTRAC_DISCONNECT_CT_LOCK_9.2" 96 301 | ;; 302 | *) # Absolutely fatal 303 | ENABLE_KILL_SERVER=1 304 | die "CONNTRAC_DISCONNECT_UNKNOWN" 98 305 | ;; 306 | esac 307 | } 308 | fi 309 | 310 | # Log failure 311 | if [ -n "${conntrac_fail}" ] || [ -n "${conntrac_error}" ]; then 312 | { 313 | if [ -f "${EASYTLS_CONN_TRAC}.fail" ]; then 314 | "${EASYTLS_CAT}" "${EASYTLS_CONN_TRAC}.fail" || \ 315 | die "Failed to read ${EASYTLS_CONN_TRAC}.fail" 316 | fi 317 | "${EASYTLS_PRINTF}" '%s ' "${local_date_ascii}" 318 | [ -z "${conntrac_fail}" ] || "${EASYTLS_PRINTF}" '%s ' "NFound" 319 | [ -z "${conntrac_error}" ] || "${EASYTLS_PRINTF}" '%s ' "ERROR" 320 | [ -z "${ip_pool_exhausted}" ] || "${EASYTLS_PRINTF}" '%s ' "IP-POOL" 321 | "${EASYTLS_PRINTF}" '%s\n' "DIS: ${conntrac_record}" 322 | } > "${EASYTLS_CONN_TRAC}.fail.tmp" || die "disconnect: conntrac file" 156 323 | "${EASYTLS_MV}" "${EASYTLS_CONN_TRAC}.fail.tmp" \ 324 | "${EASYTLS_CONN_TRAC}.fail" || die "disconnect: conntrac file" 157 325 | fi 326 | 327 | if [ -n "${conntrac_alt_fail}" ] || [ -n "${conntrac_alt_error}" ]; then 328 | { 329 | [ ! -f "${EASYTLS_CONN_TRAC}.fail" ] || \ 330 | "${EASYTLS_CAT}" "${EASYTLS_CONN_TRAC}.fail" 331 | "${EASYTLS_PRINTF}" '%s ' "${local_date_ascii}" 332 | [ -z "${conntrac_alt_fail}" ] || \ 333 | "${EASYTLS_PRINTF}" '%s ' "A-NFound" 334 | [ -z "${conntrac_alt_error}" ] || \ 335 | "${EASYTLS_PRINTF}" '% s ' "A-ERROR" 336 | [ -z "${ip_pool_exhausted}" ] || \ 337 | "${EASYTLS_PRINTF}" '%s ' "IP-POOL" 338 | "${EASYTLS_PRINTF}" '%s\n' "DIS: ${conntrac_alt_rec}" 339 | } > "${EASYTLS_CONN_TRAC}.fail.tmp" || die "disconnect: conntrac file" 158 340 | "${EASYTLS_MV}" "${EASYTLS_CONN_TRAC}.fail.tmp" \ 341 | "${EASYTLS_CONN_TRAC}.fail" || die "disconnect: conntrac file" 159 342 | fi 343 | 344 | # Capture env 345 | if [ -n "${log_env}" ]; then 346 | env_file="${temp_stub}-client-disconnect.env" 347 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 348 | set > "${env_file}" || die "disconnect: env" 167 349 | else 350 | env > "${env_file}" || die "disconnect: env" 168 351 | fi 352 | unset -v env_file 353 | fi 354 | 355 | # This error is currently absolutely fatal 356 | # If IP pool exhausted then ignore conntrac_alt_fail 357 | if [ -z "${ip_pool_exhausted}" ] && [ -n "${conntrac_alt_fail}" ]; then 358 | ENABLE_KILL_SERVER=1 359 | die "disconnect: conntrac_alt_fail" 169 360 | fi 361 | 362 | # OpenVPN Bug #160 363 | if [ -n "${conntrac_fail}" ]; then 364 | if [ -n "${ip_pool_exhausted}" ]; then 365 | # Ignored 366 | update_status "IP_POOL_EXHAUSTED IGNORED" 367 | else 368 | # Recovered from fail - Add your plugin 369 | : 370 | #update_status "disconnect: recovered" 371 | fi 372 | else 373 | # conntrac worked - Add your plugin 374 | : 375 | #update_status "disconnect: succeeded" 376 | fi 377 | unset -v \ 378 | conntrac_fail conntrac_alt_fail \ 379 | conntrac_error conntrac_alt_error \ 380 | ip_pool_exhausted log_env 381 | } # => update_conntrac () 382 | 383 | # Stack down 384 | stack_down () 385 | { 386 | [ -z "${stack_completed}" ] || die "STACK_DOWN CAN ONLY RUN ONCE" 161 387 | stack_completed=1 388 | 389 | # Lock 390 | acquire_lock "${easytls_lock_stub}-stack.d" || \ 391 | die "acquire_lock:stack FAIL" 99 392 | update_status "stack-lock-acquired" 393 | 394 | # Only required if this file exists 395 | if [ -f "${client_md_file_stack}" ]; then 396 | 397 | unset -v stack_err 398 | i=1 399 | p=0 400 | s='' 401 | 402 | while [ -f "${client_md_file_stack}_${i}" ]; do 403 | [ "${i}" -eq 1 ] || s="${s}." 404 | p="${i}" 405 | i="$(( i + 1 ))" 406 | done 407 | 408 | if [ "${p}" -eq 0 ]; then 409 | "${EASYTLS_RM}" "${client_md_file_stack}" || stack_err=1 410 | else 411 | "${EASYTLS_RM}" "${client_md_file_stack}_${p}" || stack_err=1 412 | fi 413 | fi 414 | 415 | # Unlock 416 | release_lock "${easytls_lock_stub}-stack.d" || \ 417 | die "release_lock:stack FAIL" 99 418 | update_status "stack-lock-released" 419 | # Save pies 420 | unset -v i p s 421 | 422 | [ -z "${stack_err}" ] || die "STACK_DOWN_FULL_ERROR" 160 423 | } # => stack_down () 424 | 425 | # Log stale files 426 | stale_error () 427 | { 428 | [ -n "${ENABLE_STALE_LOG}" ] || return 0 429 | "${EASYTLS_PRINTF}" '%s\n' "${1}" >> "${EASYTLS_SE_XLOG}" 430 | } 431 | 432 | # TLSKEY tracking .. because .. 433 | tlskey_status () 434 | { 435 | [ -n "${EASYTLS_TLSKEY_STATUS}" ] || return 0 436 | { 437 | # shellcheck disable=SC2154 438 | "${EASYTLS_PRINTF}" '%s %s %s %s\n' "${local_date_ascii}" \ 439 | "${UV_TLSKEY_SERIAL:-TLSAC}" "[dis]${1}" \ 440 | "${common_name} ${UV_REAL_NAME}" 441 | } >> "${EASYTLS_TK_XLOG}" 442 | } # => tlskey_status () 443 | 444 | # Retry pause 445 | retry_pause () 446 | { 447 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 448 | ping -n 1 127.0.0.1 449 | else 450 | sleep 1 451 | fi 452 | } # => retry_pause () 453 | 454 | # Simple lock dir 455 | acquire_lock () 456 | { 457 | [ -n "${1}" ] || return 1 458 | unset -v lock_acquired 459 | lock_attempt="${LOCK_TIMEOUT}" 460 | set -o noclobber 461 | while [ "${lock_attempt}" -gt 0 ]; do 462 | [ "${lock_attempt}" -eq "${LOCK_TIMEOUT}" ] || retry_pause 463 | lock_attempt="$(( lock_attempt - 1 ))" 464 | "${EASYTLS_MKDIR}" "${1}" || continue 465 | lock_acquired=1 466 | break 467 | done 468 | set +o noclobber 469 | [ -n "${lock_acquired}" ] || return 1 470 | } # => acquire_lock () 471 | 472 | # Release lock 473 | release_lock () 474 | { 475 | [ -d "${1}" ] || return 0 476 | "${EASYTLS_RM}" -r "${1}" 477 | } # => release_lock () 478 | 479 | # Initialise 480 | init () 481 | { 482 | # Fail by design 483 | absolute_fail=1 484 | 485 | # Defaults 486 | if [ -z "${EASYTLS_UNIT_TEST}" ]; then 487 | EASYTLS_srv_pid="${PPID}" 488 | else 489 | EASYTLS_srv_pid=999 490 | fi 491 | 492 | # Log message 493 | status_msg="* EasyTLS-client-disconnect" 494 | 495 | # Identify Windows 496 | # shellcheck disable=SC2016 497 | EASYRSA_KSH='@(#)MIRBSD KSH R39-w32-beta14 $Date: 2013/06/28 21:28:57 $' 498 | # shellcheck disable=SC2154 499 | if [ "${KSH_VERSION}" = "${EASYRSA_KSH}" ]; then 500 | EASYTLS_FOR_WINDOWS=1 501 | fi 502 | 503 | # Required binaries 504 | EASYTLS_OPENSSL='openssl' 505 | EASYTLS_AWK='awk' 506 | EASYTLS_CAT='cat' 507 | EASYTLS_DATE='date' 508 | EASYTLS_GREP='grep' 509 | EASYTLS_MKDIR='mkdir' 510 | EASYTLS_MV='mv' 511 | EASYTLS_SED='sed' 512 | EASYTLS_PRINTF='printf' 513 | EASYTLS_RM='rm' 514 | 515 | # Directories and files 516 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 517 | # Windows 518 | host_drv="${PATH%%\:*}" 519 | base_dir="${EASYTLS_base_dir:-${host_drv}:/Progra~1/Openvpn}" 520 | EASYTLS_ersabin_dir="${EASYTLS_ersabin_dir:-${base_dir}/easy-rsa/bin}" 521 | EASYTLS_ovpnbin_dir="${EASYTLS_ovpnbin_dir:-${base_dir}/bin}" 522 | 523 | [ -d "${base_dir}" ] || exit 61 524 | [ -d "${EASYTLS_ersabin_dir}" ] || exit 62 525 | [ -d "${EASYTLS_ovpnbin_dir}" ] || exit 63 526 | [ -f "${EASYTLS_ovpnbin_dir}/${EASYTLS_OPENSSL}.exe" ] || exit 64 527 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_AWK}.exe" ] || exit 65 528 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_CAT}.exe" ] || exit 65 529 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_DATE}.exe" ] || exit 66 530 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_GREP}.exe" ] || exit 67 531 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_MKDIR}.exe" ] || exit 72 532 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_MV}.exe" ] || exit 71 533 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_SED}.exe" ] || exit 68 534 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_PRINTF}.exe" ] || exit 69 535 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_RM}.exe" ] || exit 70 536 | 537 | export PATH="${EASYTLS_ersabin_dir};${EASYTLS_ovpnbin_dir};${PATH}" 538 | fi 539 | } # => init () 540 | 541 | # Dependancies 542 | deps () 543 | { 544 | # Source vars file 545 | prog_dir="${0%/*}" 546 | EASYTLS_WORK_DIR="${EASYTLS_WORK_DIR:-${prog_dir}}" 547 | default_vars="${EASYTLS_WORK_DIR}/easytls-client-disconnect.vars" 548 | EASYTLS_VARS_FILE="${EASYTLS_VARS_FILE:-${default_vars}}" 549 | if [ -f "${EASYTLS_VARS_FILE}" ]; then 550 | # .vars-example is correct for shellcheck 551 | # shellcheck source=examples/easytls-client-disconnect.vars-example 552 | . "${EASYTLS_VARS_FILE}" || die "Source failed: ${EASYTLS_VARS_FILE}" 77 553 | update_status "vars loaded" 554 | else 555 | [ -z "${EASYTLS_REQUIRE_VARS}" ] || \ 556 | die "Missing file: ${EASYTLS_VARS_FILE}" 77 557 | fi 558 | unset -v default_vars EASYTLS_VARS_FILE EASYTLS_REQUIRE_VARS prog_dir lib_file 559 | 560 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 561 | WIN_TEMP="${host_drv}:/Windows/Temp" 562 | export EASYTLS_tmp_dir="${EASYTLS_tmp_dir:-${WIN_TEMP}}" 563 | else 564 | export EASYTLS_tmp_dir="${EASYTLS_tmp_dir:-/tmp}" 565 | fi 566 | 567 | # Test temp dir 568 | [ -d "${EASYTLS_tmp_dir}" ] || exit 60 569 | 570 | # Temp files name stub 571 | temp_stub="${EASYTLS_tmp_dir}/easytls-${EASYTLS_srv_pid}" 572 | 573 | # Lock dir 574 | easytls_lock_stub="${temp_stub}-lock" 575 | LOCK_TIMEOUT="${LOCK_TIMEOUT:-30}" 576 | 577 | # Need the date/time .. 578 | #full_date="$("${EASYTLS_DATE}" '+%s %Y/%m/%d-%H:%M:%S')" 579 | # shellcheck disable=SC2154 580 | full_date="${time_ascii}" 581 | local_date_ascii="${full_date% *}" 582 | local_time_ascii="${full_date#* }" 583 | 584 | # Windows log 585 | EASYTLS_WLOG="${temp_stub}-client-disconnect.log" 586 | 587 | # Xtra logs - TLS Key status & Stack Errors 588 | EASYTLS_TK_XLOG="${temp_stub}-tcv2-ct.x-log" 589 | EASYTLS_SE_XLOG="${temp_stub}-tcv2-se.x-log" 590 | 591 | # Temp file age before stale 592 | EASYTLS_STALE_SEC="${EASYTLS_STALE_SEC:-240}" 593 | 594 | # Conn track 595 | EASYTLS_CONN_TRAC="${temp_stub}-conn-trac" 596 | 597 | # Kill server file 598 | if [ -f "${temp_stub}-die" ]; then 599 | "${EASYTLS_PRINTF}" '%s\n' "Kill Server Signal -> exit CD" 600 | exit 9 601 | fi 602 | 603 | # Kill client file 604 | EASYTLS_KILL_FILE="${temp_stub}-kill-client" 605 | } 606 | 607 | 608 | 609 | ####################################### 610 | 611 | # Initialise 612 | init 613 | 614 | # Options 615 | while [ -n "${1}" ]; do 616 | # Separate option from value: 617 | opt="${1%%=*}" 618 | val="${1#*=}" 619 | empty_ok="" # Empty values are not allowed unless expected 620 | 621 | case "${opt}" in 622 | help|-h|--help) 623 | empty_ok=1 624 | help_text 625 | ;; 626 | -V|--version) 627 | easytls_version 628 | exit 9 629 | ;; 630 | -v|--verbose) 631 | empty_ok=1 632 | EASYTLS_VERBOSE=1 633 | ;; 634 | -s|--source-vars) 635 | empty_ok=1 636 | EASYTLS_REQUIRE_VARS=1 637 | case "${val}" in 638 | -s|--source-vars) 639 | unset -v EASYTLS_VARS_FILE ;; 640 | *) 641 | EASYTLS_VARS_FILE="${val}" ;; 642 | esac 643 | ;; 644 | -w|--work-dir) 645 | EASYTLS_WORK_DIR="${val}" 646 | ;; 647 | -t|--tmp-dir) 648 | EASYTLS_tmp_dir="${val}" 649 | ;; 650 | -b|--base-dir) 651 | EASYTLS_base_dir="${val}" 652 | ;; 653 | -o|--openvpn-bin-dir) 654 | EASYTLS_ovpnbin_dir="${val}" 655 | ;; 656 | -e|--easyrsa-bin-dir) 657 | EASYTLS_ersabin_dir="${val}" 658 | ;; 659 | *) 660 | empty_ok=1 661 | if [ -f "${opt}" ]; then 662 | # Do not need this in the log but keep it here for reference 663 | #[ -n "${EASYTLS_VERBOSE}" ] && echo "Ignoring temp file: $opt" 664 | : 665 | else 666 | warn_die "Unknown option: ${opt}" 667 | fi 668 | ;; 669 | esac 670 | 671 | # fatal error when no value was provided 672 | if [ -z "${empty_ok}" ] && { [ "${val}" = "${1}" ] || [ -z "${val}" ]; } 673 | then 674 | warn_die "Missing value to option: ${opt}" 675 | fi 676 | shift 677 | done 678 | 679 | # Report and die on fatal warnings 680 | warn_die 681 | 682 | # Dependencies 683 | deps 684 | 685 | # Write env file 686 | if [ -n "${WRITE_ENV}" ]; then 687 | env_file="${temp_stub}-client-disconnect.env" 688 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 689 | set > "${env_file}" 690 | else 691 | env > "${env_file}" 692 | fi 693 | unset -v env_file WRITE_ENV 694 | fi 695 | 696 | # Update log message 697 | # shellcheck disable=SC2154 # common_name 698 | update_status "CN: ${common_name}" 699 | 700 | # Set Client certificate serial number from Openvpn env 701 | # shellcheck disable=SC2154 702 | client_serial="$(format_number "${tls_serial_hex_0}")" 703 | 704 | # Verify Client certificate serial number 705 | [ -n "${client_serial}" ] || { 706 | help_note="Openvpn failed to pass a client serial number" 707 | die "NO CLIENT SERIAL" 8 708 | } 709 | 710 | # Fixed file for TLS-CV2 711 | if [ -n "${UV_TLSKEY_SERIAL}" ]; then 712 | client_md_file_stack="${temp_stub}-tcv2-metadata-${UV_TLSKEY_SERIAL}" 713 | update_status "tls key serial: ${UV_TLSKEY_SERIAL}" 714 | else 715 | no_uv_tlskey_serial=1 716 | fi 717 | 718 | # Clear old stack now - because there is still a stack problem 719 | # Could be the script or openvpn 720 | if [ -n "${no_uv_tlskey_serial}" ]; then 721 | # TLS-AUTH/Crypt does not stack up 722 | : 723 | else 724 | stack_down || die "stack_down FAIL" 165 725 | fi 726 | 727 | # disconnect can not fail .. 728 | disconnect_accepted 729 | 730 | # conntrac disconnect 731 | if [ -n "${ENABLE_CONN_TRAC}" ]; then 732 | update_conntrac || die "update_conntrac" 170 733 | else 734 | #update_status "conn-trac disabled" 735 | : 736 | fi 737 | 738 | # Any failure_msg means fail_and_exit 739 | [ -z "${failure_msg}" ] || fail_and_exit "NEIN: ${failure_msg}" 9 740 | 741 | # For DUBUG 742 | if [ -n "${FORCE_ABSOLUTE_FAIL}" ]; then 743 | absolute_fail=1 744 | failure_msg="FORCE_ABSOLUTE_FAIL" 745 | fi 746 | 747 | # There is only one way out of this... 748 | if [ "${absolute_fail}" -eq 0 ]; then 749 | # Delete all temp files 750 | delete_metadata_files 751 | 752 | # TLSKEY disconnect log 753 | tlskey_status "<< D-OK" 754 | 755 | # All is well 756 | verbose_print "${local_date_ascii} ${status_msg}" 757 | [ -z "${EASYTLS_FOR_WINDOWS}" ] || "${EASYTLS_PRINTF}" "%s\n" \ 758 | "${status_msg}" > "${EASYTLS_WLOG}" 759 | exit 0 760 | fi 761 | 762 | # Otherwise 763 | fail_and_exit "ABSOLUTE FAIL" 9 764 | -------------------------------------------------------------------------------- /easytls-conntrac.lib: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Experimental - Use at your own risk 4 | 5 | # Copyright - negotiable 6 | # 7 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 8 | # easytls-conntrac.lib -- Do simple magic 9 | # 10 | # Copyright (C) 2020 Richard Bonhomme (Friday 13th of March 2020) 11 | # https://github.com/TinCanTech/easy-tls 12 | # tincantech@protonmail.com 13 | # All Rights reserved. 14 | # 15 | # This code is released under version 2 of the GNU GPL 16 | # See LICENSE of this project for full licensing details. 17 | # 18 | # Connection tracking. 19 | # 20 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 21 | # 22 | 23 | # Connection tacking - Connect 24 | conn_trac_connect () 25 | { 26 | [ -n "${1}" ] || return 1 27 | [ -n "${2}" ] || return 1 28 | easytls_ct_lock_file="${2}.lock" 29 | easytls_temp_file="${2}.tmp" 30 | easytls_ct_log="${2}.log" 31 | unset -v err_exit record_found ct_ig_ipp_ex \ 32 | ct_tlskey_found ct_tlskey_duplicate 33 | 34 | acquire_lock "${easytls_ct_lock_file}" 7 || return 9 35 | 36 | if [ -n "${ENABLE_CONN_TRAC_STATS}" ]; then 37 | conn_trac_stats || { 38 | update_status "conntrac: stats fail" 39 | release_lock "${easytls_ct_lock_file}" 7 || return 9 40 | } 41 | fi 42 | 43 | # Patterns to match - Anything after ++ cannot be used 44 | ct_pattern="${1%++*}" 45 | [ -z "${VERBOSE_CONN_TRAC}" ] || \ 46 | update_status "conntrac: pattern ${ct_pattern}" 47 | 48 | ct_tlskey="${1%%=*}" 49 | if [ "${ct_tlskey}" = "TLSAC" ]; then unset -v ct_tlskey; fi 50 | 51 | if [ -f "${2}" ]; then 52 | { 53 | # shellcheck disable=2162 # read without -r 54 | while read full_conn; do 55 | 56 | conn="${full_conn%++*}" 57 | tksn="${full_conn%%=*}" 58 | 59 | [ ! "${tksn}" = "${ct_tlskey}" ] || ct_tlskey_found=1 60 | 61 | if [ "${conn}" = "${ct_pattern}" ]; then 62 | # Log - only the first time - and count duplicate 63 | [ -n "${record_found}" ] || { 64 | update_status "conntrac: already registered" 65 | } 66 | ct_tlskey_duplicate=$(( ct_tlskey_duplicate + 1 )) 67 | # IP exhausted is one way to get a duplicate 68 | # otherwise, openvpn hands out unique VPN IPs 69 | # other ways; client time-out during connecting 70 | [ -z "${ip_pool_exhausted}" ] || \ 71 | ct_ig_ipp_ex="${ct_ig_ipp_ex}." 72 | # Duplicate, because ct will add the same again 73 | record_found=1 74 | # shellcheck disable=2154 75 | "${EASYTLS_PRINTF}" '%s\n' "${full_conn}" 76 | else 77 | # Print the existing record 78 | "${EASYTLS_PRINTF}" '%s\n' "${full_conn}" 79 | fi 80 | done < "${2}" 81 | 82 | # Always register the record 83 | "${EASYTLS_PRINTF}" "%s\n" "${1}" 84 | 85 | # Add Ignore stats 86 | [ -z "${ct_ig_ipp_ex}" ] || { 87 | ct_ig_ipp_ex="${ct_ig_ipp_ex%.}" 88 | update_status "IGN-IPP-EX: ${ct_tlskey_duplicate}" 89 | tlskey_status \ 90 | " | ^^ ct: dup-TLSK: ${ct_ig_ipp_ex}${ct_tlskey_duplicate} -" 91 | } 92 | 93 | } > "${easytls_temp_file}" || err_exit=1 94 | 95 | # shellcheck disable=2154 96 | "${EASYTLS_MV}" -f "${easytls_temp_file}" "${2}" || err_exit=1 97 | 98 | # This was used for #160/1434 - Re-think it soon 99 | if [ -n "${record_found}" ]; then 100 | # IP exhausted 101 | : 102 | else 103 | update_status "conntrac: registered" 104 | tlskey_status " | > ct: register -" 105 | fi 106 | else 107 | # conntrac file does not exist, create it now 108 | "${EASYTLS_PRINTF}" "%s\n" "${1}" > "${2}" || err_exit=1 109 | update_status "conntrac: OPENED registered" 110 | tlskey_status " * ct: *OPENED* -" 111 | tlskey_status " | > ct: register -" 112 | fi 113 | release_lock "${easytls_ct_lock_file}" 7 || return 9 114 | 115 | err_exit="${err_exit:-0}" 116 | [ "${err_exit}" -eq 0 ] && [ -n "${ct_tlskey_found}" ] && err_exit=6 117 | unset -v easytls_ct_lock_file easytls_temp_file conn record_found \ 118 | ct_ig_ipp_ex ct_tlskey_found ct_tlskey_duplicate 119 | return "${err_exit}" 120 | } # => conn_trac_connect () 121 | 122 | # Update connection tacking - disconnect 123 | conn_trac_disconnect () 124 | { 125 | [ -n "${1}" ] || return 1 126 | [ -n "${2}" ] || return 1 127 | easytls_ct_lock_file="${2}.lock" 128 | easytls_temp_file="${2}.tmp" 129 | easytls_ct_log="${2}.log" 130 | unset -v err_exit record_found ct_ig_ipp_ex 131 | 132 | acquire_lock "${easytls_ct_lock_file}" 7 || return 9 133 | 134 | if [ -n "${ENABLE_CONN_TRAC_STATS}" ]; then 135 | conn_trac_stats || { 136 | update_status "conntrac: stats fail" 137 | release_lock "${easytls_ct_lock_file}" 7 || return 9 138 | } 139 | fi 140 | 141 | # Pattern to match - Anything after ++ cannot be used 142 | ct_pattern="${1%%++*}" 143 | [ -z "${VERBOSE_CONN_TRAC}" ] || \ 144 | update_status "conntrac pattern: ${ct_pattern}" 145 | 146 | if [ -f "${2}" ]; then 147 | { 148 | # shellcheck disable=2162 # read without -r 149 | while read full_conn; do 150 | 151 | conn="${full_conn%%++*}" 152 | if [ "${conn}" = "${ct_pattern}" ]; then 153 | # If record_found then a record has been deleted 154 | # Print the remaining duplicates 155 | [ -z "${record_found}" ] || \ 156 | "${EASYTLS_PRINTF}" '%s\n' "${full_conn}" 157 | if [ -n "${record_found}" ] && [ -n "${ip_pool_exhausted}" ] 158 | then 159 | ct_ig_ipp_ex="${ct_ig_ipp_ex}." 160 | fi 161 | # Matched - Do not Print 162 | [ -n "${record_found}" ] || { 163 | update_status "conntrac: unregistered" 164 | tlskey_status " |< ct: unregist -" 165 | } 166 | record_found=1 167 | else 168 | # No match - Print current record 169 | "${EASYTLS_PRINTF}" '%s\n' "${full_conn}" 170 | fi 171 | done < "${2}" 172 | 173 | # Add Ignore stats 174 | [ -z "${ct_ig_ipp_ex}" ] || { 175 | update_status "IGN-IPP-EX: ${ct_ig_ipp_ex}" 176 | tlskey_status " | ^^ ct: TLSK-DUP: ${ct_ig_ipp_ex} -" 177 | } 178 | 179 | } > "${easytls_temp_file}" || err_exit=1 180 | 181 | "${EASYTLS_MV}" -f "${easytls_temp_file}" "${2}" || err_exit=1 182 | 183 | [ -n "${record_found}" ] || { 184 | update_status "conntrac: record not found" 185 | err_exit=${err_exit:-2} 186 | } 187 | [ -s "${2}" ] || { 188 | # shellcheck disable=2154 189 | "${EASYTLS_RM}" -f "${2}" 190 | update_status "conntrac: CLOSED" 191 | tlskey_status " >X< * ct: *CLOSED* -" 192 | } 193 | else 194 | update_status "conntrac: file not found" 195 | err_exit=3 196 | fi 197 | release_lock "${easytls_ct_lock_file}" 7 || return 9 198 | 199 | err_exit="${err_exit:-0}" 200 | unset -v easytls_ct_lock_file easytls_temp_file conn \ 201 | record_found ct_ig_ipp_ex 202 | return "${err_exit}" 203 | } # => conn_trac_disconnect () 204 | 205 | # Keep statistics 206 | conn_trac_stats () 207 | { 208 | ctc=0 209 | # shellcheck disable=2154 210 | [ ! -f "${easytls_ct_log}" ] || ctc="$("${EASYTLS_CAT}" "${easytls_ct_log}")" 211 | [ $(( ctc )) -lt 4294967296 ] || ctc=0 212 | ctc=$(( ctc + 1 )) 213 | "${EASYTLS_PRINTF}" '%s\n' "${ctc}" > "${easytls_temp_file}" || return 1 214 | "${EASYTLS_MV}" -f "${easytls_temp_file}" "${easytls_ct_log}" || return 1 215 | #update_status "conntrac: tallied" 216 | tlskey_status " |; ct: tallied -" 217 | } # => conn_trac_stats () 218 | -------------------------------------------------------------------------------- /easytls-cryptv2-verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EASYTLS_VERSION="2.8.0" 4 | 5 | # Copyright - negotiable 6 | # 7 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 8 | # easytls-cryptv2-verify.sh -- Do simple magic 9 | # 10 | # Copyright (C) 2020 Richard Bonhomme (Friday 13th of March 2020) 11 | # https://github.com/TinCanTech/easy-tls 12 | # tincantech@protonmail.com 13 | # All Rights reserved. 14 | # 15 | # This code is released under version 2 of the GNU GPL 16 | # See LICENSE of this project for full licensing details. 17 | # 18 | # Acknowledgement: 19 | # syzzer: https://github.com/OpenVPN/openvpn/blob/master/doc/tls-crypt-v2.txt 20 | # 21 | # Verify: 22 | # metadata version 23 | # metadata custom group 24 | # TLS key age 25 | # Identity (CA Fingerprint) 26 | # disabled list 27 | # Client certificate serial number 28 | # * via certificate revokation list (Default) 29 | # * via OpenSSL CA (Not recommended) 30 | # * via OpenSSL index.txt (Preferred) 31 | # 32 | # VERBATUM_COPYRIGHT_HEADER_INCLUDE_NEGOTIABLE 33 | # 34 | 35 | # Help 36 | help_text () 37 | { 38 | help_msg=" 39 | easytls-cryptv2-verify.sh 40 | 41 | This script is intended to be used by tls-crypt-v2 client keys 42 | generated by Easy-TLS. See: https://github.com/TinCanTech/easy-tls 43 | 44 | Options: 45 | help|-h|--help This help text. 46 | -V|--version 47 | -v|--verbose Be a lot more verbose at run time (Not Windows). 48 | -c|--ca= CA directory *REQUIRED* 49 | -z|--no-ca Run in No CA mode. Still requires --ca= 50 | -g|--custom-group= 51 | Verify the client metadata against a custom group. 52 | -s|--source-vars= 53 | Force Easy-TLS to source a vars file. 54 | The default vars file is sourced if no FILENAME is given. 55 | -x|--max-tlskey-age= 56 | TLS Crypt V2 Key allowable age in days (default: 1825). 57 | To disable age check use 0 58 | -y|--tlskey-hash Verify metadata hash (TLS-key serial number). 59 | -d|--disable-list Disable the temporary disabled-list check. 60 | -k|--kill-client Use easytls-client-connect script to kill client. 61 | Killing a client can only be done once a client has 62 | connected, so a failed connection must roll-over, then 63 | easytls-client-connect.sh immediately kills the client. 64 | --v1|--via-crl Do X509 certificate checks via X509_METHOD 1, CRL check. 65 | --v2|--via-ca Do X509 certificate checks via X509_METHOD 2, 66 | Use 'OpenSSL ca' commands. NOT SUPPORTED 67 | --v3|--via-index Do X509 certificate checks via X509_METHOD 3, 68 | Search OpenSSL index.txt PREFERRED 69 | This method does not require loading the OpenSSL binary. 70 | -a|--cache-id Use the saved CA-Identity from EasyTLS. 71 | -p|--preload-id= 72 | Preload the CA-Identity when calling the script. 73 | -w|--work-dir= Path to Easy-TLS scripts and vars for this server. 74 | -t|--tmp-dir= Temp directory where server-scripts write data. 75 | Default: *nix /tmp/easytls 76 | Windows C:/Windows/Temp/easytls 77 | -b|--base-dir= Path to OpenVPN base directory. (Windows Only) 78 | Default: C:/Progra~1/OpenVPN 79 | -o|--ovpnbin-dir= Path to OpenVPN bin directory. (Windows Only) 80 | Default: C:/Progra~1/OpenVPN/bin 81 | -e|--ersabin-dir= Path to Easy-RSA3 bin directory. (Windows Only) 82 | Default: C:/Progra~1/Openvpn/easy-rsa/bin 83 | 84 | Exit codes: 85 | 0 - Allow connection, Client key has passed all tests. 86 | 2 - Disallow connection, client key has passed all tests but is REVOKED. 87 | 3 - Disallow connection, TLS key serial number is disabled. 88 | 4 - Disallow connection, TLS key has expired. 89 | 5 - Disallow connection, local/remote Custom Groups do not match. 90 | 6 - Disallow connection, local/remote Identities do not match. 91 | 7 - Disallow connection, invalid metadata_version field. 92 | 8 - Dissalow connection, failed to read metadata_file 93 | 9 - BUG Disallow connection, general script failure. 94 | 10 - ERROR Disallow connection, client TLS key has unknown serial number. 95 | 11 - ERROR Disallow connection, client TLS key has invalid serial number. 96 | 12 - ERROR Disallow connection, missing remote Identity. 97 | 13 - ERROR Disallow connection, missing local Identity. (Unlucky) 98 | 21 - USER ERROR Disallow connection, options error. 99 | 22 - USER ERROR Disallow connection, failed to set --ca *REQUIRED*. 100 | 23 - USER ERROR Disallow connection, missing CA certificate. 101 | 24 - USER ERROR Disallow connection, missing CRL file. 102 | 25 - USER ERROR Disallow connection, missing index.txt. 103 | 26 - USER ERROR Disallow connection, missing safessl-easyrsa.cnf. 104 | 27 - USER ERROR Disallow connection, missing EasyTLS disabled list. 105 | 28 - USER ERROR Disallow connection, missing openvpn server metadata_file. 106 | 29 - USER ERROR Disallow connection, Invalid value for --tls-age. 107 | 30 - USER ERROR Disallow connection, missing EasyTLS data dir. 108 | 33 - USER ERROR Disallow connection, missing EasyTLS CA Identity file. 109 | 34 - USER ERROR Disallow connection, Invalid --cache-id and --preload-cache-id 110 | 35 - USER ERROR Disallow connection, missing easy-rsa binary directory. 111 | 36 - USER ERROR Disallow connection, missing openvpn binary directory. 112 | 60 - USER ERROR Disallow connection, missing Temp dir 113 | 61 - USER ERROR Disallow connection, missing Base dir 114 | 62 - USER ERROR Disallow connection, missing Easy-RSA bin dir 115 | 63 - USER ERROR Disallow connection, missing Openvpn bin dir 116 | 64 - USER ERROR Disallow connection, missing openssl.exe 117 | 65 - USER ERROR Disallow connection, missing cat.exe 118 | 66 - USER ERROR Disallow connection, missing date.exe 119 | 67 - USER ERROR Disallow connection, missing grep.exe 120 | 68 - USER ERROR Disallow connection, missing sed.exe 121 | 69 - USER ERROR Disallow connection, missing printf.exe 122 | 70 - USER ERROR Disallow connection, missing rm.exe 123 | 71 - USER ERROR Disallow connection, missing metadata.lib 124 | 72 - USER ERROR Disallow connection, missing mkdir.exe 125 | 126 | 77 - BUG Disallow connection, failed to sources vars file 127 | 78 - USER ERROR Disallow connection, missing vars file 128 | 89 - BUG Disallow connection, failed to create client_md_file_stack 129 | 101 - BUG Disallow connection, stale metadata file. 130 | 112 - BUG Disallow connection, invalid date 131 | 113 - BUG Disallow connection, missing dependency file. 132 | 114 - BUG Disallow connection, missing dependency file. 133 | 115 - BUG Disallow connection, missing dependency file. 134 | 116 - BUG Disallow connection, missing dependency file. 135 | 117 - BUG Disallow connection, missing dependency file. 136 | 118 - BUG Disallow connection, missing dependency file. 137 | 119 - BUG Disallow connection, missing dependency file. 138 | 121 - BUG Disallow connection, client serial number is not in CA database. 139 | 122 - BUG Disallow connection, failed to verify CRL. 140 | 123 - BUG Disallow connection, failed to verify CA. 141 | 127 - BUG Disallow connection, duplicate serial number in CA database. 142 | 128 - BUG Disallow connection, duplicate serial number in CA database. v2 143 | 129 - BUG Disallow connection, Serial status via CA has broken. 144 | 130 - BUG Disallow connection, unknown X509 method. 145 | 253 - Disallow connection, exit code when --help is called. 146 | 254 - BUG Disallow connection, fail_and_exit exited with default error code. 147 | 255 - BUG Disallow connection, die exited with default error code. 148 | " 149 | print "$help_msg" 150 | 151 | # For secrity, --help must exit with an error 152 | exit 253 153 | } # => help_text () 154 | 155 | # Wrapper around 'printf' - clobber 'print' since it's not POSIX anyway 156 | # shellcheck disable=SC1117 157 | print () { "${EASYTLS_PRINTF}" "%s\n" "${1}"; } 158 | verbose_print () 159 | { 160 | [ -n "${EASYTLS_VERBOSE}" ] || return 0 161 | print "${1}" 162 | print "" 163 | } # => verbose_print () 164 | 165 | # Set the Easy-TLS version 166 | easytls_version () 167 | { 168 | verbose_print 169 | print "Easy-TLS version: ${EASYTLS_VERSION}" 170 | verbose_print 171 | } # => easytls_version () 172 | 173 | # Exit on error 174 | die () 175 | { 176 | # TLSKEY connect log 177 | tlskey_status "FATAL" || update_status "tlskey_status FATAL" 178 | 179 | #delete_metadata_files 180 | easytls_version 181 | [ -z "${help_note}" ] || print "${help_note}" 182 | [ -z "${err_msg}" ] || print "${err_msg}" 183 | verbose_print " ${status_msg}" 184 | print "ERROR: ${1}" 185 | if [ -n "${ENABLE_KILL_SERVER}" ]; then 186 | echo 1 > "${temp_stub}-die" 187 | echo 'XXXXX CV2 XXXXX KILL SERVER' 188 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 189 | "${EASYTLS_PRINTF}" "%s\n%s\n" \ 190 | " ${status_msg}" "ERROR: ${1}" > "${EASYTLS_WLOG}" 191 | taskkill /F /PID "${EASYTLS_srv_pid}" 192 | else 193 | kill -15 "${EASYTLS_srv_pid}" 194 | fi 195 | fi 196 | exit "${2:-255}" 197 | } # => die () 198 | 199 | # Tls-crypt-v2-verify failure, not an error. 200 | fail_and_exit () 201 | { 202 | # Unlock 203 | if release_lock "${easytls_lock_stub}-v2.d"; then 204 | update_status "v2-lock-released" 205 | else 206 | update_status "v2-fail_and_exit:release_lock-FAIL" 207 | fi 208 | 209 | delete_metadata_files 210 | 211 | # shellcheck disable=SC2154 212 | if [ -n "${EASYTLS_VERBOSE}" ]; then 213 | print "${status_msg}" 214 | print "${failure_msg}" 215 | print "${1}" 216 | print "* ==> version local: ${local_easytls}" 217 | print "* ==> version remote: ${MD_EASYTLS}" 218 | print "* ==> custom_group local: ${LOCAL_CUSTOM_G}" 219 | print "* ==> custom_group remote: ${MD_CUSTOM_G}" 220 | print "* ==> identity local: ${local_identity}" 221 | print "* ==> identity remote: ${MD_IDENTITY}" 222 | print "* ==> X509 serial remote: ${MD_x509_SERIAL}" 223 | print "* ==> name remote: ${MD_NAME}" 224 | print "* ==> TLSK serial remote: ${MD_TLSKEY_SERIAL}" 225 | print "* ==> sub-key remote: ${MD_SUBKEY}" 226 | print "* ==> date remote: ${MD_DATE}" 227 | [ "${2}" -eq 2 ] && print "* ==> Client serial status: revoked" 228 | [ "${2}" -eq 3 ] && print "* ==> Client serial status: disabled" 229 | [ -z "${help_note}" ] || print "${help_note}" 230 | else 231 | print "${status_msg}" 232 | print "${failure_msg}" 233 | print "${1}" 234 | fi 235 | 236 | # TLSKEY connect log 237 | tlskey_status "*V! FAIL" || update_status "tlskey_status FAIL" 238 | 239 | [ -z "${EASYTLS_FOR_WINDOWS}" ] || "${EASYTLS_PRINTF}" "%s %s %s %s\n" \ 240 | " ${status_msg}" "${failure_msg}" "${1}" \ 241 | "ENABLE_KILL_CLIENT: ${ENABLE_KILL_CLIENT:-0}" > "${EASYTLS_WLOG}" 242 | 243 | [ -z "${ENABLE_KILL_CLIENT}" ] || { 244 | # Create kill client file 245 | "${EASYTLS_PRINTF}" "%s\n" "${MD_x509_SERIAL}" > "${EASYTLS_KILL_FILE}" 246 | # Create metadata file for client-connect or kill-client 247 | write_metadata_file 248 | # Exit without error to kill client 249 | exit 0 250 | } 251 | 252 | exit "${2:-254}" 253 | } # => fail_and_exit () 254 | 255 | # Delete all metadata files 256 | delete_metadata_files () 257 | { 258 | [ -n "${keep_metadata}" ] || { 259 | "${EASYTLS_RM}" -f "${client_md_file_stack}" 260 | update_status "temp-files deleted" 261 | } 262 | } # => delete_metadata_files () 263 | 264 | # Log fatal warnings 265 | warn_die () 266 | { 267 | if [ -n "${1}" ]; then 268 | fatal_msg="${fatal_msg} 269 | ${1}" 270 | else 271 | [ -z "${fatal_msg}" ] || die "${fatal_msg}" 21 272 | fi 273 | } # => warn_die () 274 | 275 | # Update status message 276 | update_status () 277 | { 278 | status_msg="${status_msg} => ${*}" 279 | } # => update_status () 280 | 281 | # Verify CA 282 | verify_ca () 283 | { 284 | "${EASYTLS_OPENSSL}" x509 -in "${ca_cert}" -noout 285 | } # => verify_ca () 286 | 287 | # Local identity 288 | fn_local_identity () 289 | { 290 | "${EASYTLS_OPENSSL}" x509 -in "${ca_cert}" \ 291 | -noout -SHA256 -fingerprint | \ 292 | "${EASYTLS_SED}" -e 's/^.*=//g' -e 's/://g' 293 | } # => fn_local_identity () 294 | 295 | # Verify CRL 296 | verify_crl () 297 | { 298 | "${EASYTLS_OPENSSL}" crl -in "${crl_pem}" -noout 299 | } # => verify_crl () 300 | 301 | # Decode CRL 302 | fn_read_crl () 303 | { 304 | "${EASYTLS_OPENSSL}" crl -in "${crl_pem}" -noout -text 305 | } # => fn_read_crl () 306 | 307 | # Search CRL for client cert serial number 308 | fn_search_crl () 309 | { 310 | "${EASYTLS_PRINTF}" "%s\n" "${crl_text}" | \ 311 | "${EASYTLS_GREP}" -c "^[[:blank:]]*Serial Number: ${MD_x509_SERIAL}$" 312 | } # => fn_search_crl () 313 | 314 | # Final check: Search index.txt for Valid client cert serial number 315 | fn_search_index () 316 | { 317 | "${EASYTLS_GREP}" -c \ 318 | "^V.*[[:blank:]]${MD_x509_SERIAL}[[:blank:]].*/CN=${MD_NAME}.*$" \ 319 | "${index_txt}" 320 | } # => fn_search_index () 321 | 322 | # Check metadata client certificate serial number against CRL 323 | serial_status_via_crl () 324 | { 325 | client_cert_revoked="$(fn_search_crl)" 326 | case "${client_cert_revoked}" in 327 | 0) 328 | # Final check: Is this serial in index.txt and Valid 329 | case "$(fn_search_index)" in 330 | 0) 331 | failure_msg="Serial number is not in the CA database:" 332 | fail_and_exit "SERIAL NUMBER UNKNOWN" 121 333 | ;; 334 | 1) 335 | client_passed_x509_tests 336 | ;; 337 | *) 338 | die "Duplicate serial numbers: ${MD_x509_SERIAL}" 127 339 | ;; 340 | esac 341 | ;; 342 | 1) 343 | client_passed_x509_tests_certificate_revoked 344 | ;; 345 | *) 346 | insert_msg="Duplicate serial numbers detected:" 347 | failure_msg="${insert_msg} ${MD_x509_SERIAL}" 348 | die "Duplicate serial numbers: ${MD_x509_SERIAL}" 128 349 | ;; 350 | esac 351 | } # => serial_status_via_crl () 352 | 353 | # Check metadata client certificate serial number against CA 354 | serial_status_via_ca () 355 | { 356 | # This is non-functional until OpenSSL is fixed 357 | verify_openssl_serial_status 358 | 359 | # Get serial status via CA 360 | # Forget that returns an error because of OpenSSL 361 | client_cert_serno_status="$(openssl_serial_status)" 362 | 363 | # Format serial status 364 | # Deliberately over-write the previous value 365 | client_cert_serno_status="$(capture_serial_status)" 366 | client_cert_serno_status="${client_cert_serno_status% *}" 367 | client_cert_serno_status="${client_cert_serno_status##*=}" 368 | 369 | # Considering what has to be done, I don't like this 370 | case "${client_cert_serno_status}" in 371 | Valid) 372 | client_passed_x509_tests 373 | ;; 374 | Revoked) 375 | client_passed_x509_tests_certificate_revoked 376 | ;; 377 | *) 378 | die "Serial status via CA has broken" 129 379 | ;; 380 | esac 381 | } # => serial_status_via_ca () 382 | 383 | # Use OpenSSL to return certificate serial number status 384 | openssl_serial_status () 385 | { 386 | # OpenSSL ALWAYS exit with error - but here I do not care 387 | # And will NOT defend against error 388 | "${EASYTLS_OPENSSL}" ca -cert "${ca_cert}" -config "${openssl_cnf}" \ 389 | -status "${MD_x509_SERIAL}" 2>&1 || : # Ignore error 390 | } # => openssl_serial_status () 391 | 392 | # Capture serial status 393 | capture_serial_status () 394 | { 395 | "${EASYTLS_PRINTF}" "%s\n" "${client_cert_serno_status}" | \ 396 | "${EASYTLS_GREP}" '^.*=.*$' 397 | } # => capture_serial_status () 398 | 399 | # Verify OpenSSL serial status returns ok 400 | verify_openssl_serial_status () 401 | { 402 | return 0 # Disable this `return` if you want to test 403 | # OpenSSL appears to always exit with error - have not solved this 404 | # OpenSSL 3.0.1 is just as obtuse .. 405 | "${EASYTLS_OPENSSL}" ca -cert "${ca_cert}" -config "${openssl_cnf}" \ 406 | -status "${MD_x509_SERIAL}" || \ 407 | die "OpenSSL returned an error exit code" 101 408 | 409 | # This is why I am not using CA, from `man 1 ca` 410 | : << MAN_OPENSSL_CA 411 | WARNINGS 412 | The ca command is quirky and at times downright unfriendly. 413 | 414 | The ca utility was originally meant as an example of how to do things 415 | in a CA. It was not supposed to be used as a full blown CA itself: 416 | nevertheless some people are using it for this purpose. 417 | 418 | The ca command is effectively a single user command: no locking is 419 | done on the various files and attempts to run more than one ca command 420 | on the same database can have unpredictable results. 421 | MAN_OPENSSL_CA 422 | # This script ONLY reads, .: I am hoping for better than 'unpredictable' ;-) 423 | } # => verify_openssl_serial_status () 424 | 425 | # Check metadata client certificate serial number against index.txt 426 | serial_status_via_pki_index () 427 | { 428 | # This needs improvement 429 | is_valid="$(fn_search_valid_pki_index)" 430 | is_revoked="$(fn_search_revoked_pki_index)" 431 | if [ "${is_revoked}" -eq 0 ]; then 432 | if [ "${is_valid}" -eq 1 ]; then 433 | client_passed_x509_tests 434 | else 435 | # Cert is not known 436 | insert_msg="Serial number is not in the CA database:" 437 | failure_msg="${insert_msg} ${MD_x509_SERIAL}" 438 | fail_and_exit "SERIAL NUMBER UNKNOWN" 121 439 | fi 440 | else 441 | client_passed_x509_tests_certificate_revoked 442 | fi 443 | } # => serial_status_via_pki_index () 444 | 445 | # Final check: Search index.txt for Valid client cert serial number 446 | fn_search_valid_pki_index () 447 | { 448 | "${EASYTLS_GREP}" -c \ 449 | "^V.*[[:blank:]]${MD_x509_SERIAL}[[:blank:]].*\/CN=${MD_NAME}.*$" \ 450 | "${index_txt}" 451 | } # => fn_search_valid_pki_index () 452 | 453 | # Final check: Search index.txt for Revoked client cert serial number 454 | fn_search_revoked_pki_index () 455 | { 456 | "${EASYTLS_GREP}" -c \ 457 | "^R.*[[:blank:]]${MD_x509_SERIAL}[[:blank:]].*\/CN=${MD_NAME}.*$" \ 458 | "${index_txt}" 459 | } # => fn_search_revoked_pki_index () 460 | 461 | # This is the long way to connect - X509 462 | client_passed_x509_tests () 463 | { 464 | insert_msg="Client certificate is recognised and Valid:" 465 | update_status "${insert_msg} ${MD_x509_SERIAL}" 466 | } # => client_passed_x509_tests () 467 | 468 | # This is the only way to fail for Revokation - X509 469 | client_passed_x509_tests_certificate_revoked () 470 | { 471 | insert_msg="Client certificate is revoked:" 472 | failure_msg="${insert_msg} ${MD_x509_SERIAL}" 473 | fail_and_exit "CERTIFICATE REVOKED" 2 474 | } # => client_passed_x509_tests_certificate_revoked () 475 | 476 | # This is the best way to connect - TLS only 477 | client_passed_tls_tests_connection_allowed () 478 | { 479 | absolute_fail=0 480 | update_status "connection allowed" 481 | } # => client_passed_tls_tests_connection_allowed () 482 | 483 | # Allow connection 484 | connection_allowed () 485 | { 486 | absolute_fail=0 487 | update_status "connection allowed" 488 | } # => connection_allowed () 489 | 490 | # Retry pause 491 | retry_pause () 492 | { 493 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 494 | ping -n 1 127.0.0.1 495 | else 496 | sleep 1 497 | fi 498 | } # => retry_pause () 499 | 500 | # Simple lock dir 501 | acquire_lock () 502 | { 503 | [ -n "${1}" ] || return 1 504 | unset -v lock_acquired 505 | lock_attempt="${LOCK_TIMEOUT}" 506 | set -o noclobber 507 | while [ "${lock_attempt}" -gt 0 ]; do 508 | [ "${lock_attempt}" -eq "${LOCK_TIMEOUT}" ] || retry_pause 509 | lock_attempt=$(( lock_attempt - 1 )) 510 | "${EASYTLS_MKDIR}" "${1}" || continue 511 | lock_acquired=1 512 | break 513 | done 514 | set +o noclobber 515 | [ -n "${lock_acquired}" ] || return 1 516 | } # => acquire_lock () 517 | 518 | # Release lock 519 | release_lock () 520 | { 521 | [ -d "${1}" ] || return 0 522 | "${EASYTLS_RM}" -r "${1}" 523 | } # => release_lock () 524 | 525 | # Write metadata file 526 | write_metadata_file () 527 | { 528 | # Set the client_md_file_stack 529 | client_md_file_stack="${temp_stub}-tcv2-metadata-${MD_TLSKEY_SERIAL}" 530 | 531 | # Lock 532 | acquire_lock "${easytls_lock_stub}-stack.d" || \ 533 | die "acquire_lock:stack FAIL" 99 534 | update_status "stack-lock-acquired" 535 | 536 | # Stack up duplicate metadata files - check for stale_stack 537 | unset -v stale_stack 538 | if [ -f "${client_md_file_stack}" ]; then 539 | stack_up || die "stack_up" 160 540 | fi 541 | 542 | if [ -n "${stale_stack}" ]; then 543 | update_status "stale_stack" 544 | if [ -n "${ENABLE_STALE_LOG}" ]; then 545 | EASYTLS_stale_log="${temp_stub}-stale.x-log" 546 | "${EASYTLS_PRINTF}" '%s\n' \ 547 | "${local_date_ascii} - ${client_md_file_stack}" \ 548 | >> "${EASYTLS_stale_log}" || : 549 | fi 550 | else 551 | if [ -f "${client_md_file_stack}" ]; then 552 | # If client_md_file_stack still exists then fail 553 | update_status "STALE_FILE_ERROR" 554 | keep_metadata=1 555 | die "STALE_FILE_ERROR" 101 556 | else 557 | # Otherwise stack-up 558 | "${EASYTLS_CP}" "${OPENVPN_METADATA_FILE}" \ 559 | "${client_md_file_stack}" || \ 560 | die "Failed to update client_md_file_stack" 89 561 | update_status "Created client_md_file_stack" 562 | fi 563 | fi 564 | 565 | # Lock 566 | release_lock "${easytls_lock_stub}-stack.d" || \ 567 | die "release_lock:stack FAIL" 99 568 | update_status "stack-lock-released" 569 | } # => write_metadata_file () 570 | 571 | # Stack up 572 | stack_up () 573 | { 574 | [ -z "${stack_completed}" ] || die "STACK_UP CAN ONLY RUN ONCE" 161 575 | stack_completed=1 576 | 577 | # No Stack UP - No stack in stand alone mode 578 | [ -z "${EASYTLS_STAND_ALONE}" ] || return 0 579 | 580 | f_date="$("${EASYTLS_DATE}" +%s -r "${client_md_file_stack}")" 581 | unset -v stale_stack 582 | if [ $(( local_time_unix - f_date )) -gt 60 ]; then 583 | stale_stack=1 584 | return 0 585 | fi 586 | 587 | # Full Stack UP 588 | i=1 589 | s='' 590 | while [ -f "${client_md_file_stack}_${i}" ]; do 591 | s="${s}." 592 | i=$(( i + 1 )) 593 | done 594 | client_md_file_stack="${client_md_file_stack}_${i}" 595 | s="${s}${i}" 596 | 597 | update_status "stack-up" 598 | tlskey_status " | => stack:+ ${s} -" 599 | } # => stack_up () 600 | 601 | # TLSKEY tracking .. because .. 602 | tlskey_status () 603 | { 604 | [ -n "${EASYTLS_TLSKEY_STATUS}" ] || return 0 605 | { 606 | # shellcheck disable=SC2154 607 | "${EASYTLS_PRINTF}" '%s %s %s %s\n' "${local_date_ascii}" \ 608 | "${MD_TLSKEY_SERIAL}" "*VF >${1}" "${MD_NAME}" 609 | } >> "${EASYTLS_TK_XLOG}" 610 | } # => tlskey_status () 611 | 612 | # easytls-metadata.lib 613 | #=# 35579017-b084-4d6b-94d5-76397c2d4a1f 614 | 615 | # Break metadata_string into variables 616 | # shellcheck disable=SC2034 # foo appears unused. Verify it or export it. 617 | metadata_string_to_vars () 618 | { 619 | MD_TLSKEY_SERIAL="${1%%-*}" || return 1 620 | 621 | #seed="${*}" || return 1 622 | #MD_SEED="${seed#*-}" || return 1 623 | #unset -v seed 624 | 625 | #md_padding="${md_seed%%--*}" || return 1 626 | md_easytls_ver="${1#*--}" || return 1 627 | MD_EASYTLS="${md_easytls_ver%-*}" || return 1 628 | unset -v md_easytls_ver 629 | 630 | MD_IDENTITY="${2%%-*}" || return 1 631 | MD_SRV_NAME="${2##*-}" || return 1 632 | MD_x509_SERIAL="${3}" || return 1 633 | MD_DATE="${4}" || return 1 634 | MD_CUSTOM_G="${5}" || return 1 635 | MD_NAME="${6}" || return 1 636 | MD_SUBKEY="${7}" || return 1 637 | MD_OPT="${8}" || return 1 638 | MD_FILTERS="${9}" || return 1 639 | } # => metadata_string_to_vars () 640 | 641 | # Break metadata string at delimeter: New Newline, old space 642 | # shellcheck disable=SC2034 # foo appears unused. Verify it or export it. 643 | metadata_stov_safe () 644 | { 645 | [ -n "$1" ] || return 1 646 | input="$1" 647 | 648 | # Not using IFS 649 | err_msg="Unspecified delimiter" 650 | delim_save="${delimiter}" 651 | delimiter="${delimiter:-${newline}}" 652 | [ -n "${delimiter}" ] || return 1 653 | case "${input}" in 654 | *"${delimiter}"*) : ;; 655 | *) delimiter=' ' 656 | esac 657 | 658 | MD_SEED="${input#*-}" 659 | 660 | # Expansions inside ${..} need to be quoted separately, 661 | # otherwise they will match as a pattern. 662 | # Which is the required behaviour. 663 | # shellcheck disable=SC2295 664 | { # Required group for shellcheck 665 | m1="${input%%${delimiter}*}" 666 | input="${input#*${delimiter}}" 667 | m2="${input%%${delimiter}*}" 668 | input="${input#*${delimiter}}" 669 | m3="${input%%${delimiter}*}" 670 | input="${input#*${delimiter}}" 671 | m4="${input%%${delimiter}*}" 672 | input="${input#*${delimiter}}" 673 | m5="${input%%${delimiter}*}" 674 | input="${input#*${delimiter}}" 675 | m6="${input%%${delimiter}*}" 676 | input="${input#*${delimiter}}" 677 | m7="${input%%${delimiter}*}" 678 | input="${input#*${delimiter}}" 679 | m8="${input%%${delimiter}*}" 680 | input="${input#*${delimiter}}" 681 | m9="${input%%${delimiter}*}" 682 | input="${input#*${delimiter}}" 683 | } 684 | 685 | # An extra space has been used, probably in the name 686 | err_msg="metadata-lib: ${m9} vs ${input}" 687 | [ "${m9}" = "${input}" ] || return 1 688 | 689 | delimiter="${delim_save}" 690 | 691 | err_msg="metadata-lib: metadata_string_to_vars" 692 | metadata_string_to_vars "$m1" "$m2" "$m3" "$m4" \ 693 | "$m5" "$m6" "$m7" "$m8" "$m9" || return 1 694 | unset -v m1 m2 m3 m4 m5 m6 m7 m8 m9 input err_msg 695 | } # => metadata_stov_safe () 696 | 697 | #=# 70b4ec32-f1fc-47fb-a261-f02e7f572b62 698 | 699 | # Initialise 700 | init () 701 | { 702 | # Fail by design 703 | absolute_fail=1 704 | delimiter=' 705 | ' 706 | 707 | # metadata version 708 | local_easytls='easytls' 709 | 710 | # TLS expiry age (days) Default 5 years, 1825 days 711 | TLSKEY_MAX_AGE=$((365*5)) 712 | 713 | # Defaults 714 | if [ -z "${EASYTLS_UNIT_TEST}" ]; then 715 | EASYTLS_srv_pid="$PPID" 716 | else 717 | EASYTLS_srv_pid=999 718 | fi 719 | 720 | # metadata file 721 | # shellcheck disable=SC2154 722 | OPENVPN_METADATA_FILE="${metadata_file}" 723 | 724 | # Log message 725 | status_msg="* Easy-TLS-cryptv2-verify" 726 | 727 | # X509 is disabled by default 728 | # To enable use command line option: 729 | # --v1|--via-crl - client serial revokation via CRL search (Default) 730 | # --v2|--via-ca - client serial revokation via OpenSSL ca command (Broken) 731 | # --v3|--via-index - client serial revokation via index.txt search (Preferred) 732 | X509_METHOD=0 733 | 734 | # Identify Windows 735 | # shellcheck disable=SC2016 736 | EASYRSA_KSH='@(#)MIRBSD KSH R39-w32-beta14 $Date: 2013/06/28 21:28:57 $' 737 | # shellcheck disable=SC2154 738 | if [ "${KSH_VERSION}" = "${EASYRSA_KSH}" ]; then 739 | EASYTLS_FOR_WINDOWS=1 740 | fi 741 | 742 | # Required binaries 743 | EASYTLS_OPENSSL='openssl' 744 | EASYTLS_CAT='cat' 745 | EASYTLS_CP='cp' 746 | EASYTLS_DATE='date' 747 | EASYTLS_GREP='grep' 748 | EASYTLS_MKDIR='mkdir' 749 | EASYTLS_MV='mv' 750 | EASYTLS_SED='sed' 751 | EASYTLS_PRINTF='printf' 752 | EASYTLS_RM='rm' 753 | 754 | # Directories and files 755 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 756 | # Windows 757 | host_drv="${PATH%%\:*}" 758 | base_dir="${EASYTLS_base_dir:-${host_drv}:/Progra~1/Openvpn}" 759 | EASYTLS_ersabin_dir="${EASYTLS_ersabin_dir:-${base_dir}/easy-rsa/bin}" 760 | EASYTLS_ovpnbin_dir="${EASYTLS_ovpnbin_dir:-${base_dir}/bin}" 761 | 762 | [ -d "${base_dir}" ] || exit 61 763 | [ -d "${EASYTLS_ersabin_dir}" ] || exit 62 764 | [ -d "${EASYTLS_ovpnbin_dir}" ] || exit 63 765 | [ -f "${EASYTLS_ovpnbin_dir}/${EASYTLS_OPENSSL}.exe" ] || exit 64 766 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_CAT}.exe" ] || exit 65 767 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_CP}.exe" ] || exit 65 768 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_DATE}.exe" ] || exit 66 769 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_GREP}.exe" ] || exit 67 770 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_MKDIR}.exe" ] || exit 72 771 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_MV}.exe" ] || exit 71 772 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_SED}.exe" ] || exit 68 773 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_PRINTF}.exe" ] || exit 69 774 | [ -f "${EASYTLS_ersabin_dir}/${EASYTLS_RM}.exe" ] || exit 70 775 | 776 | export PATH="${EASYTLS_ersabin_dir};${EASYTLS_ovpnbin_dir};${PATH}" 777 | fi 778 | } # => init () 779 | 780 | # Dependancies 781 | deps () 782 | { 783 | # OpenVPN only provides a minimal shell for --tls-crypt-v2 784 | # Thus, this extra loop to jump through to source vars 785 | # Also, vars MUST be loaded successfully. 786 | # Source vars file 787 | prog_dir="${0%/*}" 788 | EASYTLS_WORK_DIR="${EASYTLS_WORK_DIR:-${prog_dir}}" 789 | default_vars="${EASYTLS_WORK_DIR}/easytls-cryptv2-verify.vars" 790 | EASYTLS_VARS_FILE="${EASYTLS_VARS_FILE:-${default_vars}}" 791 | if [ -f "${EASYTLS_VARS_FILE}" ]; then 792 | # .vars-example is correct for shellcheck 793 | # shellcheck source=examples/easytls-cryptv2-verify.vars-example 794 | . "${EASYTLS_VARS_FILE}" || die "Source failed: ${EASYTLS_VARS_FILE}" 77 795 | update_status "vars loaded" 796 | else 797 | [ -z "${EASYTLS_REQUIRE_VARS}" ] || \ 798 | die "Missing file: ${EASYTLS_VARS_FILE}" 77 799 | fi 800 | 801 | # Source metadata lib 802 | lib_file="${EASYTLS_WORK_DIR}/easytls-metadata.lib" 803 | [ -f "${lib_file}" ] || \ 804 | lib_file="${EASYTLS_WORK_DIR}/dev/easytls-metadata.lib" 805 | if [ -f "${lib_file}" ]; then 806 | # shellcheck source=dev/easytls-metadata.lib 807 | . "${lib_file}" || die "Failed to source: ${lib_file}" 808 | easytls_metadata_lib_ver 809 | fi 810 | 811 | unset -v default_vars EASYTLS_VARS_FILE EASYTLS_REQUIRE_VARS prog_dir lib_file 812 | 813 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 814 | WIN_TEMP="${host_drv}:/Windows/Temp" 815 | export EASYTLS_tmp_dir="${EASYTLS_tmp_dir:-${WIN_TEMP}}" 816 | else 817 | export EASYTLS_tmp_dir="${EASYTLS_tmp_dir:-/tmp}" 818 | fi 819 | 820 | # Test temp dir 821 | [ -d "${EASYTLS_tmp_dir}" ] || exit 60 822 | 823 | # Temp files name stub 824 | temp_stub="${EASYTLS_tmp_dir}/easytls-${EASYTLS_srv_pid}" 825 | 826 | # Lock dir 827 | easytls_lock_stub="${temp_stub}-lock" 828 | LOCK_TIMEOUT="${LOCK_TIMEOUT:-30}" 829 | 830 | # Lock 831 | acquire_lock "${easytls_lock_stub}-v2.d" || \ 832 | die "acquire_lock:v2 FAIL" 99 833 | update_status "V2-lock-acquired" 834 | 835 | # Windows log 836 | EASYTLS_WLOG="${temp_stub}-cryptv2-verify.log" 837 | EASYTLS_TK_XLOG="${temp_stub}-tcv2-ct.x-log" 838 | 839 | # Kill client file 840 | EASYTLS_KILL_FILE="${temp_stub}-kill-client" 841 | 842 | # HASH 843 | EASYTLS_HASH_ALGO="${EASYTLS_HASH_ALGO:-SHA256}" 844 | 845 | # CA_DIR MUST be set with option: -c|--ca 846 | [ -d "${CA_DIR}" ] || die "Path to CA directory is required, see help" 22 847 | 848 | # Easy-TLS required files 849 | TLS_dir="${CA_DIR}/easytls/data" 850 | disabled_list="${TLS_dir}/easytls-disabled-list.txt" 851 | tlskey_serial_index="${TLS_dir}/easytls-key-index.txt" 852 | 853 | # Check TLS files 854 | [ -d "${TLS_dir}" ] || { 855 | help_note="Use './easytls init [no-ca]" 856 | die "Missing EasyTLS dir: ${TLS_dir}" 30 857 | } 858 | 859 | # CA required files 860 | ca_cert="${CA_DIR}/ca.crt" 861 | ca_identity_file="${TLS_dir}/easytls-ca-identity.txt" 862 | crl_pem="${CA_DIR}/crl.pem" 863 | index_txt="${CA_DIR}/index.txt" 864 | openssl_cnf="${CA_DIR}/safessl-easyrsa.cnf" 865 | 866 | # Check X509 files 867 | if [ -n "${EASYTLS_NO_CA}" ]; then 868 | # Do not need CA cert 869 | # Cannot do any X509 verification 870 | : 871 | else 872 | # Need CA cert 873 | [ -f "${ca_cert}" ] || { 874 | help_note="This script requires an EasyRSA generated CA." 875 | die "Missing CA certificate: ${ca_cert}" 23 876 | } 877 | 878 | if [ -n "${use_cache_id}" ]; then 879 | # This can soon be deprecated 880 | [ -f "${ca_identity_file}" ] || { 881 | help_note="This script requires an EasyTLS generated CA identity." 882 | die "Missing CA identity: ${ca_identity_file}" 33 883 | } 884 | fi 885 | 886 | # Check for either --cache-id or --preload-cache-id 887 | # Do NOT allow both 888 | if [ -n "${use_cache_id}" ] && [ -n "${PRELOAD_CA_ID}" ]; then 889 | die "Cannot use --cache-id and --preload-cache-id together." 34 890 | fi 891 | 892 | if [ ! "${X509_METHOD}" -eq 0 ]; then 893 | # Only check these files if using x509 894 | [ -f "${crl_pem}" ] || { 895 | help_note="This script requires an EasyRSA generated CRL." 896 | die "Missing CRL: ${crl_pem}" 24 897 | } 898 | 899 | [ -f "${index_txt}" ] || { 900 | help_note="This script requires an EasyRSA generated DB." 901 | die "Missing index.txt: ${index_txt}" 25 902 | } 903 | 904 | [ -f "${openssl_cnf}" ] || { 905 | help_note="This script requires an EasyRSA generated PKI." 906 | die "Missing OpenSSL config: ${openssl_cnf}" 26 907 | } 908 | fi 909 | fi # X509 checks 910 | 911 | # Ensure that TLS expiry age is numeric 912 | case "${TLSKEY_MAX_AGE}" in 913 | ''|*[!0-9]*) # Invalid value 914 | die "Invalid value for --tls-age: ${TLSKEY_MAX_AGE}" 29 915 | ;; 916 | *) # Valid value 917 | # maximum age in seconds 918 | tlskey_expire_age_sec=$((TLSKEY_MAX_AGE*60*60*24)) 919 | ;; 920 | esac 921 | 922 | # Default CUSTOM_GROUP 923 | [ -n "${LOCAL_CUSTOM_G}" ] || LOCAL_CUSTOM_G='EASYTLS' 924 | 925 | # Need the date/time .. 926 | full_date="$("${EASYTLS_DATE}" '+%s %Y/%m/%d-%H:%M:%S')" 927 | local_date_ascii="${full_date##* }" 928 | local_time_unix="${full_date%% *}" 929 | 930 | # Must be set by openvpn 931 | # If the script fails for metadata file then 932 | # - All pre-flight checks completed 933 | # - Script is ready to run 934 | [ -f "${OPENVPN_METADATA_FILE}" ] || { 935 | help_note="This script can ONLY be used by a running openvpn server." 936 | die "Missing: OPENVPN_METADATA_FILE: ${OPENVPN_METADATA_FILE}" 28 937 | } 938 | } # => deps () 939 | 940 | ####################################### 941 | 942 | # Initialise 943 | init 944 | 945 | # Options 946 | while [ -n "${1}" ]; do 947 | # Separate option from value: 948 | opt="${1%%=*}" 949 | val="${1#*=}" 950 | empty_ok="" # Empty values are not allowed unless expected 951 | 952 | case "${opt}" in 953 | help|-h|--help) 954 | help_text 955 | ;; 956 | -V|--version) 957 | easytls_version 958 | exit 9 959 | ;; 960 | -v|--verbose) 961 | empty_ok=1 962 | EASYTLS_VERBOSE=1 963 | ;; 964 | -l) 965 | empty_ok=1 966 | EASYTLS_STAND_ALONE=1 967 | ;; 968 | -c|--ca) 969 | CA_DIR="${val}" 970 | ;; 971 | -z|--no-ca) 972 | empty_ok=1 973 | EASYTLS_NO_CA=1 974 | ;; 975 | -w|--work-dir) 976 | EASYTLS_WORK_DIR="${val}" 977 | ;; 978 | -s|--source-vars) 979 | empty_ok=1 980 | EASYTLS_REQUIRE_VARS=1 981 | case "${val}" in 982 | -s|--source-vars) 983 | unset -v EASYTLS_VARS_FILE ;; 984 | *) 985 | EASYTLS_VARS_FILE="${val}" ;; 986 | esac 987 | ;; 988 | -g|--custom-group) 989 | if [ -z "${LOCAL_CUSTOM_G}" ]; then 990 | LOCAL_CUSTOM_G="${val}" 991 | else 992 | ENABLE_MULTI_CUSTOM_G=1 993 | LOCAL_CUSTOM_G="${val} ${LOCAL_CUSTOM_G}" 994 | fi 995 | ;; 996 | -x|--max-tlskey-age) 997 | TLSKEY_MAX_AGE="${val}" 998 | ;; 999 | -d|--disable-list) 1000 | empty_ok=1 1001 | IGNORE_DISABLED_LIST=1 1002 | ;; 1003 | -k|--kill-client) # Use client-connect to kill client 1004 | empty_ok=1 1005 | ENABLE_KILL_CLIENT=1 1006 | ;; 1007 | -y|--tlskey-hash) 1008 | empty_ok=1 1009 | ENABLE_TLSKEY_HASH=1 1010 | ;; 1011 | --hash) 1012 | EASYTLS_HASH_ALGO="${val}" 1013 | ;; 1014 | --v1|--via-crl) 1015 | empty_ok=1 1016 | update_status "(crl)" 1017 | X509_METHOD=1 1018 | ;; 1019 | --v2|--via-ca) 1020 | empty_ok=1 1021 | update_status "(ca)" 1022 | X509_METHOD=2 1023 | ;; 1024 | --v3|--via-index) 1025 | empty_ok=1 1026 | update_status "(index)" 1027 | X509_METHOD=3 1028 | ;; 1029 | -a|--cache-id) 1030 | empty_ok=1 1031 | use_cache_id=1 1032 | ;; 1033 | -p|--preload-id) 1034 | PRELOAD_CA_ID="${val}" 1035 | ;; 1036 | -t|--tmp-dir) 1037 | EASYTLS_tmp_dir="${val}" 1038 | ;; 1039 | -b|--base-dir) 1040 | EASYTLS_base_dir="${val}" 1041 | ;; 1042 | -o|--openvpn-bin-dir) 1043 | EASYTLS_ovpnbin_dir="${val}" 1044 | ;; 1045 | -e|--easyrsa-bin-dir) 1046 | EASYTLS_ersabin_dir="${val}" 1047 | ;; 1048 | *) 1049 | warn_die "Unknown option: ${1}" 1050 | ;; 1051 | esac 1052 | 1053 | # fatal error when no value was provided 1054 | if [ -z "${empty_ok}" ] && { [ "${val}" = "${1}" ] || [ -z "${val}" ]; } 1055 | then 1056 | warn_die "Missing value to option: ${opt}" 1057 | fi 1058 | shift 1059 | done 1060 | 1061 | # Report and die on fatal warnings 1062 | warn_die 1063 | 1064 | # Dependancies 1065 | deps 1066 | 1067 | # Write env file 1068 | if [ -n "${WRITE_ENV}" ]; then 1069 | env_file="${temp_stub}-cryptv2-verify.env" 1070 | if [ -n "${EASYTLS_FOR_WINDOWS}" ]; then 1071 | set > "${env_file}" 1072 | else 1073 | env > "${env_file}" 1074 | fi 1075 | unset -v env_file WRITE_ENV 1076 | fi 1077 | 1078 | # Get metadata 1079 | 1080 | # Get metadata_string 1081 | metadata_string="$("${EASYTLS_CAT}" "${OPENVPN_METADATA_FILE}")" || \ 1082 | die "failed to read metadata_file (1)" 8 1083 | [ -n "${metadata_string}" ] || die "failed to read metadata_file (2)" 8 1084 | 1085 | # Convert metadata string to variables 1086 | metadata_stov_safe "$metadata_string" || \ 1087 | die "metadata_string_to_vars" 87 1088 | 1089 | # Update log message 1090 | update_status "CN: ${MD_NAME}" 1091 | 1092 | # Metadata version 1093 | 1094 | # metadata_version MUST equal 'easytls' 1095 | case "${MD_EASYTLS}" in 1096 | "${local_easytls}") 1097 | update_status "${MD_EASYTLS} OK" 1098 | ;; 1099 | '') 1100 | failure_msg="metadata version is missing" 1101 | fail_and_exit "METADATA_VERSION" 7 1102 | ;; 1103 | *) 1104 | failure_msg="metadata version is not recognised: ${MD_EASYTLS}" 1105 | fail_and_exit "METADATA_VERSION" 7 1106 | ;; 1107 | esac 1108 | 1109 | # Metadata custom_group 1110 | 1111 | if [ -n "${ENABLE_MULTI_CUSTOM_G}" ]; then 1112 | # This will do for the time being .. 1113 | if "${EASYTLS_PRINTF}" "${LOCAL_CUSTOM_G}" | \ 1114 | "${EASYTLS_GREP}" -q "${MD_CUSTOM_G}" 1115 | then 1116 | update_status "MULTI custom_group ${MD_CUSTOM_G} OK" 1117 | else 1118 | failure_msg="multi_custom_g" 1119 | fail_and_exit "MULTI_CUSTOM_GROUP" 98 1120 | fi 1121 | else 1122 | # MD_CUSTOM_G MUST equal LOCAL_CUSTOM_G 1123 | case "${MD_CUSTOM_G}" in 1124 | "${LOCAL_CUSTOM_G}") 1125 | update_status "custom_group ${MD_CUSTOM_G} OK" 1126 | ;; 1127 | '') 1128 | failure_msg="metadata custom_group is missing" 1129 | fail_and_exit "METADATA_CUSTOM_GROUP" 5 1130 | ;; 1131 | *) 1132 | failure_msg="metadata custom_group is not correct: ${MD_CUSTOM_G}" 1133 | fail_and_exit "METADATA_CUSTOM_GROUP" 5 1134 | ;; 1135 | esac 1136 | fi 1137 | 1138 | # tlskey-serial checks 1139 | 1140 | if [ -n "${ENABLE_TLSKEY_HASH}" ]; then 1141 | # Verify tlskey-serial is in index 1142 | "${EASYTLS_GREP}" -q "${MD_TLSKEY_SERIAL}" "${tlskey_serial_index}" || { 1143 | failure_msg="TLS-key is not recognised" 1144 | fail_and_exit "ALIEN MD_TLSKEY_SERIAL" 10 1145 | } 1146 | 1147 | # HASH metadata sring without the tlskey-serial 1148 | md_hash="$("${EASYTLS_PRINTF}" '%s' "${MD_SEED}" | \ 1149 | "${EASYTLS_OPENSSL}" "${EASYTLS_HASH_ALGO}" -r)" 1150 | md_hash="${md_hash%% *}" 1151 | [ "${md_hash}" = "${MD_TLSKEY_SERIAL}" ] || { 1152 | failure_msg="TLS-key metadata hash is incorrect" 1153 | fail_and_exit "MD_TLSKEY_SERIAL" 11 1154 | } 1155 | 1156 | update_status "tlskey-hash verified OK" 1157 | fi 1158 | 1159 | # tlskey expired 1160 | 1161 | # Verify key date and expire by --tls-age 1162 | # Disable check if --tls-age=0 (Default age is 5 years) 1163 | if [ "${tlskey_expire_age_sec}" -gt 0 ]; then 1164 | case "${local_time_unix}" in 1165 | ''|*[!0-9]*) 1166 | # Invalid value - date.exe is missing 1167 | die "Invalid value for local_time_unix: ${local_time_unix}" 112 1168 | ;; 1169 | *) # Valid value 1170 | tlskey_expire_age_sec=$((TLSKEY_MAX_AGE*60*60*24)) 1171 | 1172 | # days since key creation 1173 | tlskey_age_sec=$(( local_time_unix - MD_DATE )) 1174 | tlskey_age_day=$(( tlskey_age_sec / (60*60*24) )) 1175 | 1176 | # Check key_age is less than --tls-age 1177 | if [ ${tlskey_age_sec} -gt ${tlskey_expire_age_sec} ] 1178 | then 1179 | max_age_msg="Max age: ${TLSKEY_MAX_AGE} days" 1180 | key_age_msg="Key age: ${tlskey_age_day} days" 1181 | failure_msg="Key expired: ${max_age_msg} ${key_age_msg}" 1182 | fail_and_exit "TLSKEY_EXPIRED" 4 1183 | fi 1184 | 1185 | update_status "Key age ${tlskey_age_day} days OK" 1186 | ;; 1187 | esac 1188 | fi 1189 | 1190 | # Disabled list 1191 | 1192 | # Check serial number is not disabled 1193 | # Use --disable-list to disable this check 1194 | if [ -n "${IGNORE_DISABLED_LIST}" ]; then 1195 | : # Ignored 1196 | else 1197 | [ -f "${disabled_list}" ] || \ 1198 | die "Missing disabled list: ${disabled_list}" 27 1199 | 1200 | # Search the disabled_list for client serial number 1201 | if "${EASYTLS_GREP}" -q "^${MD_TLSKEY_SERIAL}[[:blank:]]" \ 1202 | "${disabled_list}" 1203 | then 1204 | # Client is disabled 1205 | failure_msg="TLS key serial number is disabled: ${MD_TLSKEY_SERIAL}" 1206 | fail_and_exit "TLSKEY_DISABLED" 3 1207 | else 1208 | # Client is not disabled 1209 | update_status "Enabled OK" 1210 | fi 1211 | fi 1212 | 1213 | 1214 | # Start optional X509 checks 1215 | if [ "${X509_METHOD}" -eq 0 ]; then 1216 | # No X509 required 1217 | update_status "metadata verified" 1218 | else 1219 | 1220 | # Verify CA cert is valid and/or set the CA identity 1221 | if [ -n "${use_cache_id}" ]; then 1222 | local_identity="$("${EASYTLS_CAT}" "${ca_identity_file}")" 1223 | elif [ -n "${PRELOAD_CA_ID}" ]; then 1224 | local_identity="${PRELOAD_CA_ID}" 1225 | else 1226 | # Verify CA is valid 1227 | verify_ca || die "Bad CA ${ca_cert}" 123 1228 | 1229 | # Set Local Identity: CA fingerprint 1230 | local_identity="$(fn_local_identity)" 1231 | fi 1232 | 1233 | # local_identity is required 1234 | [ -n "${local_identity}" ] || { 1235 | failure_msg="Missing: local identity" 1236 | fail_and_exit "LOCAL IDENTITY" 13 1237 | } 1238 | 1239 | # Check metadata Identity against local Identity 1240 | if [ "${local_identity}" = "${MD_IDENTITY}" ]; then 1241 | update_status "identity OK" 1242 | else 1243 | failure_msg="identity mismatch" 1244 | fail_and_exit "IDENTITY MISMATCH" 6 1245 | fi 1246 | 1247 | 1248 | # Verify serial status 1249 | case "${X509_METHOD}" in 1250 | 1) 1251 | # Method 1 1252 | # Check metadata client certificate serial number against CRL 1253 | 1254 | # Verify CRL is valid 1255 | verify_crl || die "Bad CRL: ${crl_pem}" 122 1256 | 1257 | # Capture CRL 1258 | crl_text="$(fn_read_crl)" 1259 | 1260 | # Verify via CRL 1261 | serial_status_via_crl 1262 | ;; 1263 | 2) 1264 | # Method 2 1265 | # Check metadata client certificate serial number against CA 1266 | 1267 | # Due to OpenSSL being "what it is", it is not possible to 1268 | # reliably verify the 'OpenSSL ca' command (yet..) 1269 | 1270 | # Verify via CA 1271 | serial_status_via_ca 1272 | ;; 1273 | 3) 1274 | # Method 3 1275 | # Search OpenSSL index.txt for client serial number 1276 | # and return Valid, Revoked or not Known status 1277 | # OpenSSL is never loaded for this check 1278 | serial_status_via_pki_index 1279 | ;; 1280 | *) 1281 | die "Unknown method for verify: ${X509_METHOD}" 130 1282 | ;; 1283 | esac 1284 | 1285 | fi # => End optional X509 checks 1286 | 1287 | # Allow connection 1288 | connection_allowed 1289 | 1290 | # Any failure_msg means fail_and_exit 1291 | [ -z "${failure_msg}" ] || fail_and_exit "NEIN: ${failure_msg}" 9 1292 | 1293 | # For DUBUG 1294 | if [ -n "${FORCE_ABSOLUTE_FAIL}" ]; then 1295 | absolute_fail=1 1296 | failure_msg="FORCE_ABSOLUTE_FAIL" 1297 | fi 1298 | 1299 | # Create metadata file for client-connect or kill-client 1300 | write_metadata_file || die "Failed to write metadata-file" 1301 | 1302 | # Unlock 1303 | release_lock "${easytls_lock_stub}-v2.d" || die "release_lock:v2 FAIL" 99 1304 | update_status "v2-lock-released" 1305 | 1306 | # There is only one way out of this... 1307 | if [ "${absolute_fail}" -eq 0 ]; then 1308 | # TLSKEY connect log 1309 | tlskey_status ">>: V-OK" || update_status "tlskey_status FAIL" 1310 | 1311 | # All is well 1312 | verbose_print "${local_date_ascii} ${status_msg}" 1313 | [ -z "${EASYTLS_FOR_WINDOWS}" ] || "${EASYTLS_PRINTF}" "%s\n" \ 1314 | " ${status_msg}" > "${EASYTLS_WLOG}" 1315 | exit 0 1316 | fi 1317 | 1318 | # Otherwise 1319 | fail_and_exit "ABSOLUTE FAIL" 9 1320 | -------------------------------------------------------------------------------- /examples/easytls-client-connect.vars-example: -------------------------------------------------------------------------------- 1 | # Change settings without restarting the server 2 | # easytls-client-connect.vars-example 3 | 4 | #EASYTLS_VERBOSE=1 5 | #ENABLE_NO_CHECK=1 6 | #IGNORE_X509_MISMATCH=1 7 | #IGNORE_HWADDR_MISMATCH=1 8 | #ENFORCE_UNIQUE_TLSKEY=1 9 | #ENFORCE_TLSKEY_SERIAL_MATCH=1 10 | #ENFORCE_PUSH_HWADDR=1 11 | #ENFORCE_CRYPT_V2=1 12 | #ENFORCE_KEY_HWADDR=1 13 | #PEER_IP_MATCH=1 14 | 15 | # Openvpn dynamic client options 16 | #EASYTLS_DYN_OPTS_FILE=/etc/openvpn/server/easytls-dyn-opts 17 | 18 | # Set a specific temporary directory 19 | #EASYTLS_tmp_dir=/tmp 20 | #EASYTLS_tmp_dir=/Windows/Temp 21 | 22 | # Connection tracking 23 | #ENABLE_CONN_TRAC=1 # Also requires easytls-client-disconnect.sh 24 | #VERBOSE_CONN_TRAC=1 25 | #ENABLE_CONN_TRAC_STATS=1 26 | 27 | # Enable tlskey-status tracking 28 | #EASYTLS_TLSKEY_STATUS=1 29 | 30 | # Fine tune lock time-out 31 | #LOCK_TIMEOUT=30 32 | 33 | # Debug tools 34 | #FATAL_CONN_TRAC=1 35 | #FATAL_CONN_TRAC_2=1 36 | #POOL_EXHAUST_FATAL=1 37 | #POOL_EXHAUST_KILL_CLIENT=1 38 | #ENABLE_KILL_SERVER=1 39 | #WRITE_ENV=1 40 | 41 | -------------------------------------------------------------------------------- /examples/easytls-client-disconnect.vars-example: -------------------------------------------------------------------------------- 1 | # Change settings without restarting the server 2 | # easytls-client-disconnect.vars-example 3 | 4 | #EASYTLS_VERBOSE=1 5 | 6 | # Set a specific temporary directory 7 | #EASYTLS_tmp_dir=/tmp 8 | #EASYTLS_tmp_dir=/Windows/Temp 9 | 10 | # Connection tracking 11 | #ENABLE_CONN_TRAC=1 # Also requires easytls-client-disconnect.sh 12 | #VERBOSE_CONN_TRAC=1 13 | #ENABLE_CONN_TRAC_STATS=1 14 | 15 | # Enable tlskey-status tracking 16 | #EASYTLS_TLSKEY_STATUS=1 17 | #ENABLE_STALE_LOG=1 18 | 19 | # Fine tune lock time-out 20 | #LOCK_TIMEOUT=30 21 | 22 | # Debug tools 23 | #FATAL_CONN_TRAC=1 24 | #ENABLE_KILL_SERVER=1 25 | #WRITE_ENV=1 26 | 27 | -------------------------------------------------------------------------------- /examples/easytls-cryptv2-verify.vars-example: -------------------------------------------------------------------------------- 1 | # Change settings without restarting the server 2 | # easytls-cryptv2-verify.vars-example 3 | 4 | #EASYTLS_VERBOSE=1 5 | 6 | # Easy-TLS PKI (No-CA mode) or Easy-RSA CA directory 7 | #CA_DIR='/etc/openvpn/easyrsa/pki' 8 | 9 | # Easy-TLS No-CA mode 10 | #EASYTLS_NO_CA=1 11 | 12 | # Easy-TLS CUSTOM_GROUP 13 | #LOCAL_CUSTOM_G='EASYTLS' 14 | 15 | # Multiple CUSTOM_GROUP 16 | #LOCAL_CUSTOM_G='EASYTLS TEST' 17 | #ENABLE_MULTI_CUSTOM_G=1 18 | 19 | # TLS-Crypt-V2 key max age (5 years) 20 | #TLSKEY_MAX_AGE=1825 21 | 22 | # Verify TLS-CRYPT-V2 KEY serial-number 23 | #ENABLE_TLSKEY_HASH=1 24 | 25 | # Ignore the disabled-list 26 | #IGNORE_DISABLED_LIST=1 27 | 28 | # X509 method 29 | #X509_METHOD=1 30 | #X509_METHOD=2 31 | #X509_METHOD=3 32 | 33 | # Preload CA-ID 34 | #PRELOAD_CA_ID= 35 | 36 | # Enable/disable kill_client mode 37 | #ENABLE_KILL_CLIENT=1 38 | 39 | # Set a specific temporary directory 40 | #EASYTLS_tmp_dir=/tmp # *nix 41 | #EASYTLS_tmp_dir=C:/Windows/Temp # Win 42 | 43 | # If easytls-cryptv2-verify.sh is run stand alone then use this 44 | #EASYTLS_STAND_ALONE=1 45 | 46 | # Hash algorithm 47 | #EASYTLS_HASH_ALGO=SHA256 48 | 49 | # Write environment to temporary log file 50 | #WRITE_ENV=1 51 | 52 | # Enable tlskey-status tracking 53 | #EASYTLS_TLSKEY_STATUS=1 54 | 55 | # Enable kill server mode 56 | #ENABLE_KILL_SERVER=1 57 | 58 | # Fine tune lock time-out 59 | #LOCK_TIMEOUT=30 60 | 61 | -------------------------------------------------------------------------------- /examples/easytls-script.conf-example: -------------------------------------------------------------------------------- 1 | # Easy-TLS script configuration for OpenVPN Server 2 | 3 | # OpenVPN and EasyTLS temporary directory 4 | tmp-dir '/dev/shm/easytls' 5 | 6 | # If your clients have username/password then set this to level 3 7 | script-security 2 8 | 9 | # Easytls scripts only require -s to force loading of default vars file 10 | # All other settings are loaded via the vars file 11 | # Default vars files are '/etc/openvpn/server/${script_name}.vars' 12 | # To use an alternative vars file, specify the name with -s= 13 | tls-crypt-v2-verify '/etc/openvpn/server/easytls-cryptv2-verify.sh -s' 14 | client-connect '/etc/openvpn/server/easytls-client-connect.sh -s' 15 | client-disconnect '/etc/openvpn/server/easytls-client-disconnect.sh -s 16 | 17 | --------------------------------------------------------------------------------