├── .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 | [](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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------