Browse code

[PATCH] Change verify-cn so cn is no longer hardcoded in openvpn's config file

This patch should be easy to process.
A resubmission of the patch sent to this list on 04/23/2009.

The patch changes the verify-cn script sample
to be used with --tls-verify so that instead of having
to hardcode a cn to verify in the OpenVPN configuration file
the allowed cns may be written into a separate file.

This makes the process of verifying cns a whole
lot more dynamic, to the point where it is useful
in the real world.

One problem with this patch is that it is backwards
incompatible. I did not bother keeping the original
calling interface as A) it's a sample script, and B) the
original's functionality seems useless
and equalivant functionality is easily available
with the new script.

The problem with the original is that there seems
little point in verifying a client's cn when all
the clients share one cn, as would have to be
the case when the cn is hardcoded into the openvpn
config file.

This patch applies against the testing allmiscs branch,
and should apply against any of the other testing
branches as well.

It works for me. I've tested it throughly but not
used it extensively in production.

Regards,

Karl <kop@meme.com>

Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
Acked-by: Gert Doering <gert@greenie.muc.de>
Acked-by: Eric F Crist <ecrist@secure-computing.net>

Karl O. Pinc authored on 2010/02/19 05:30:48
Showing 1 changed files
... ...
@@ -7,24 +7,28 @@
7 7
 #
8 8
 # For example in OpenVPN, you could use the directive:
9 9
 #
10
-#   tls-verify "./verify-cn Test-Client"
10
+#   tls-verify "./verify-cn /etc/openvpn/allowed_clients"
11 11
 #
12 12
 # This would cause the connection to be dropped unless
13
-# the client common name is "Test-Client"
13
+# the client common name is listed on a line in the
14
+# allowed_clients file.
14 15
 
15
-die "usage: verify-cn cn certificate_depth X509_NAME_oneline" if (@ARGV != 3);
16
+die "usage: verify-cn cnfile certificate_depth X509_NAME_oneline" if (@ARGV != 3);
16 17
 
17 18
 # Parse out arguments:
18
-#   cn    -- The common name which the client is required to have,
19
-#            taken from the argument to the tls-verify directive
20
-#            in the OpenVPN config file.
21
-#   depth -- The current certificate chain depth.  In a typical
22
-#            bi-level chain, the root certificate will be at level
23
-#            1 and the client certificate will be at level 0.
24
-#            This script will be called separately for each level.
25
-#   x509  -- the X509 subject string as extracted by OpenVPN from
26
-#            the client's provided certificate.
27
-($cn, $depth, $x509) = @ARGV;
19
+#   cnfile -- The file containing the list of common names, one per
20
+#             line, which the client is required to have,
21
+#             taken from the argument to the tls-verify directive
22
+#             in the OpenVPN config file.
23
+#             The file can have blank lines and comment lines that begin
24
+#             with the # character.
25
+#   depth  -- The current certificate chain depth.  In a typical
26
+#             bi-level chain, the root certificate will be at level
27
+#             1 and the client certificate will be at level 0.
28
+#             This script will be called separately for each level.
29
+#   x509   -- the X509 subject string as extracted by OpenVPN from
30
+#             the client's provided certificate.
31
+($cnfile, $depth, $x509) = @ARGV;
28 32
 
29 33
 if ($depth == 0) {
30 34
     # If depth is zero, we know that this is the final
... ...
@@ -34,11 +38,19 @@ if ($depth == 0) {
34 34
     # the X509 subject string.
35 35
 
36 36
     if ($x509 =~ /\/CN=([^\/]+)/) {
37
+        $cn = $1;
37 38
 	# Accept the connection if the X509 common name
38 39
 	# string matches the passed cn argument.
39
-	if ($cn eq $1) {
40
-	    exit 0;
40
+	open(FH, '<', $cnfile) or exit 1; # can't open, nobody authenticates!
41
+        while (defined($line = <FH>)) {
42
+	    if ($line !~ /^[[:space:]]*(#|$)/o) {
43
+		chop($line);
44
+		if ($line eq $cn) {
45
+		    exit 0;
46
+		}
47
+	    }
41 48
 	}
49
+	close(FH);
42 50
     }
43 51
 
44 52
     # Authentication failed -- Either we could not parse