Browse code

Fix certificate serial number export

contrib/OCSP_check/OCSP_check.sh:
New barebone script to demonstrate how to use $tls_serial_{n}
to perform simple OCSP queries using OpenSSL command line
"openssl ocsp". Minimal sanity checks to fail if user tries to
use it without customizing.

openvpn.8:
Added some notes about $tls_serial_{n} format and usage to the
existing description.

ssl.c:
correctly manage and export serial numbers of any size (as
parsed by OpenSSL) into the environment. Set to empty string
in case of errors, as 0 and negative numbers are all possible
(although illegal) certificate serial numbers. Use an OpenSSL
BIO object to do the job. Conforms to coding style guidelines.

See the discussion at

http://article.gmane.org/gmane.network.openvpn.devel/3588

for more details.

Signed-off-by: Davide Brini <dave_br@gmx.com>
Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
Acked-by: David Sommerseth <dazo@users.sourceforge.net>

Davide Brini authored on 2010/04/27 20:20:05
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,89 @@
0
+#!/bin/sh
1
+
2
+# Sample script to perform OCSP queries with OpenSSL
3
+# given a certificate serial number.
4
+
5
+# If you run your own CA, you can set up a very simple
6
+# OCSP server using the -port option to "openssl ocsp".
7
+
8
+# Full documentation and examples:
9
+# http://www.openssl.org/docs/apps/ocsp.html
10
+
11
+
12
+# Edit the following values to suit your needs
13
+
14
+# OCSP responder URL (mandatory)
15
+# YOU MUST UNCOMMENT ONE OF THESE AND SET IT TO A VALID SERVER
16
+#ocsp_url="http://ocsp.example.com/"
17
+#ocsp_url="https://ocsp.secure.example.com/"
18
+
19
+# Path to issuer certificate (mandatory)
20
+# YOU MUST SET THIS TO THE PATH TO THE CA CERTIFICATE
21
+issuer="/path/to/CAcert.crt"
22
+
23
+# use a nonce in the query, set to "-no_nonce" to not use it
24
+nonce="-nonce"
25
+
26
+# Verify the response
27
+# YOU MUST SET THIS TO THE PATH TO THE RESPONSE VERIFICATION CERT
28
+verify="/path/to/CAcert.crt"
29
+
30
+# Depth in the certificate chain where the cert to verify is.
31
+# Set to -1 to run the verification at every level (NOTE that
32
+# in that case you need a more complex script as the various
33
+# parameters for the query will likely be different at each level)
34
+# "0" is the usual value here, where the client certificate is
35
+check_depth=0
36
+
37
+cur_depth=$1     # this is the *CURRENT* depth
38
+common_name=$2   # CN in case you need it
39
+
40
+# minimal sanity checks
41
+
42
+err=0
43
+if [ -z "$issuer" ] || [ ! -e "$issuer" ]; then
44
+  echo "Error: issuer certificate undefined or not found!" >&2
45
+  err=1
46
+fi
47
+
48
+if [ -z "$verify" ] || [ ! -e "$verify" ]; then
49
+  echo "Error: verification certificate undefined or not found!" >&2
50
+  err=1
51
+fi
52
+
53
+if [ -z "$ocsp_url" ]; then
54
+  echo "Error: OCSP server URL not defined!" >&2
55
+  err=1
56
+fi
57
+
58
+if [ $err -eq 1 ]; then
59
+  echo "Did you forget to customize the variables in the script?" >&2
60
+  exit 1
61
+fi
62
+
63
+# begin
64
+if [ $check_depth -eq -1 ] || [ $cur_depth -eq $check_depth ]; then
65
+  eval serial="\$tls_serial_${cur_depth}"
66
+
67
+  # Check that the serial is not empty
68
+  if [ -n "$serial" ]; then
69
+
70
+    # This is only an example; you are encouraged to run this command (without
71
+    # redirections) manually against your or your CA's OCSP server to see how
72
+    # it responds, and adapt accordingly.
73
+    # Sample output:
74
+    #
75
+    # Response verify OK
76
+    # 0x428740A5: good
77
+    #      This Update: Apr 24 19:38:49 2010 GMT
78
+    #      Next Update: May  2 14:23:42 2010 GMT
79
+
80
+    openssl ocsp -issuer "$issuer" \
81
+                 "$nonce" \
82
+                 -CAfile "$verify" \
83
+                 -url "$ocsp_url" \
84
+                 -serial "0x${serial}" >/dev/null 2>&1
85
+  else
86
+    exit 1
87
+  fi
88
+fi
... ...
@@ -5355,7 +5355,12 @@ where
5355 5355
 is the verification level.  Only set for TLS connections.  Set prior
5356 5356
 to execution of
5357 5357
 .B \-\-tls-verify
5358
-script.
5358
+script. This is in the form of a hex string like "37AB46E0", which is
5359
+suitable for doing serial-based OCSP queries (with OpenSSL, you have
5360
+to prepend "0x" to the string). If something goes wrong while reading
5361
+the value from the certificate it will be an empty string, so your
5362
+code should check that.
5363
+See the contrib/OCSP_check/OCSP_check.sh script for an example.
5359 5364
 .\"*********************************************************
5360 5365
 .TP
5361 5366
 .B tun_mtu
... ...
@@ -788,9 +788,30 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
788 788
 
789 789
   /* export serial number as environmental variable */
790 790
   {
791
-    const int serial = (int) ASN1_INTEGER_get (X509_get_serialNumber (ctx->current_cert));
792
-    openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", ctx->error_depth);
793
-    setenv_int (opt->es, envname, serial);
791
+    BIO *bio = NULL;
792
+    char serial[100];
793
+    int n1, n2;
794
+
795
+    CLEAR (serial);
796
+    if ((bio = BIO_new (BIO_s_mem ())) == NULL)
797
+      {
798
+        msg (M_WARN, "CALLBACK: Cannot create BIO (for tls_serial_%d)", ctx->error_depth);
799
+      }
800
+    else
801
+      {
802
+        /* "prints" the serial number onto the BIO and read it back */
803
+        if ( ! ( ( (n1 = i2a_ASN1_INTEGER(bio, X509_get_serialNumber (ctx->current_cert))) >= 0 ) &&
804
+                 ( (n2 = BIO_read (bio, serial, sizeof (serial)-1)) >= 0 ) &&
805
+                 ( n1 == n2 ) ) )
806
+          {
807
+            msg (M_WARN, "CALLBACK: Error reading/writing BIO (for tls_serial_%d)", ctx->error_depth);
808
+            CLEAR (serial);     /* empty string */
809
+          }
810
+
811
+        openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", ctx->error_depth);
812
+        setenv_str (opt->es, envname, serial);
813
+        BIO_free(bio);
814
+      }
794 815
   }
795 816
 
796 817
   /* export current untrusted IP */