[Openvpn-devel,1/4] Option --cryptoapicert: support issuer name as a selector

Message ID 20230128223421.2207802-2-selva.nair@gmail.com
State Accepted
Headers show
Series Improvements for cryptoapi.c | expand

Commit Message

Selva Nair Jan. 28, 2023, 10:34 p.m. UTC
From: Selva Nair <selva.nair@gmail.com>

- Certificate selection string can now specify a partial
  issuer name string as "--cryptoapicert ISSUER:<string>" where
  <string> is matched as a substring of the issuer (CA) name in
  the certificate.

  Partial case-insensitive matching against the "issuer name" is
  used. Here "issuer name" is a text representation of the RDN's
  separated by commas.

  E.g., "CA, Ontario, Toronto, Acme Inc., IT, Acme Root CA".

  See MSDN docs on CertFindCertificateInStore() with CERT_FIND_ISSUER_STR
  as "FindType" for more details.

  As the order of RDN's is not well-defined[*] and type names like "OU"
  or "CN" are not included, its best to match against a single attribute
  like the CN of the issuer:

  E.g., --cryptoapicert "ISSUER:Acme Root"

[*] Windows appears to order RDN's in the reverse order to which
its written in the certificate but do not rely on this.

Signed-off-by: Selva Nair <selva.nair@gmail.com>
---
 doc/man-sections/windows-options.rst | 13 +++++++++++--
 src/openvpn/cryptoapi.c              |  5 +++++
 2 files changed, 16 insertions(+), 2 deletions(-)

Comments

Gert Doering Feb. 14, 2023, 3:36 p.m. UTC | #1
Acked-by: Gert Doering <gert@greenie.muc.de>

I did hope that someone else would report back and say "I have tested this
and it works great!".  Nobody volunteered and I wanted this out of the
way (and I think it's a useful addition with very little code needed).

Code looks good according to documentation of CertFindCertificateInStore()
(though the microsoft documentation I found lacks the CERT_FIND...*_W
defines... but it's symmetric to CERT_FIND_SUBJECT_STR_W)

MinGW and GH tell me that the code compiles fine :-)

Documentation addition is good and well-understandable.

Your patch has been applied to the master and release/2.6 branch.

commit b9e0e4060798ed88d2170702f2935754616b1200 (master)
commit a8ff15ce49b69816b64387e3387b9a310891d12a (release/2.6)
Author: Selva Nair
Date:   Sat Jan 28 17:34:18 2023 -0500

     Option --cryptoapicert: support issuer name as a selector

     Signed-off-by: Selva Nair <selva.nair@gmail.com>
     Acked-by: Gert Doering <gert@greenie.muc.de>
     Message-Id: <20230128223421.2207802-2-selva.nair@gmail.com>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg26092.html
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/doc/man-sections/windows-options.rst b/doc/man-sections/windows-options.rst
index 368f7b19..e87291f4 100644
--- a/doc/man-sections/windows-options.rst
+++ b/doc/man-sections/windows-options.rst
@@ -41,13 +41,22 @@  Windows-Specific Options
 
      cryptoapicert "SUBJ:Peter Runestig"
 
-  To select a certificate, based on certificate's thumbprint:
+  To select a certificate, based on certificate's thumbprint (SHA1 hash):
   ::
 
      cryptoapicert "THUMB:f6 49 24 41 01 b4 ..."
 
   The thumbprint hex string can easily be copy-and-pasted from the Windows
-  Certificate Store GUI.
+  Certificate Store GUI. The embedded spaces in the hex string are optional.
+
+  To select a certificate based on a substring in certificate's
+  issuer name:
+  ::
+
+     cryptoapicert "ISSUER:Sample CA"
+
+  The first non-expired certificate found in the user's store or the
+  machine store that matches the select-string is used.
 
 --dhcp-release
   Ask Windows to release the TAP adapter lease on shutdown. This option
diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c
index 661a9a6d..39eeec1b 100644
--- a/src/openvpn/cryptoapi.c
+++ b/src/openvpn/cryptoapi.c
@@ -459,6 +459,11 @@  find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
         find_param = wide_string(cert_prop + 5, &gc);
         find_type = CERT_FIND_SUBJECT_STR_W;
     }
+    else if (!strncmp(cert_prop, "ISSUER:", 7))
+    {
+        find_param = wide_string(cert_prop + 7, &gc);
+        find_type = CERT_FIND_ISSUER_STR_W;
+    }
     else if (!strncmp(cert_prop, "THUMB:", 6))
     {
         const char *p;