Skip to contentSkip to conversation

Use CryptoAPI CA store

PATCH Superseded Faidon Liambotis 1 participant 1 message Dec 24, 2006

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Use CryptoAPI CA store

Hello,

Below you will find a patch that creates a new configuration option --cryptoapicastore (the naming sucks, I know...) which enables certificate verification using Windows Certificate Stores (CA and ROOT). It can be used in addition to --cafile and --capath or standalone. I have compile and briefly runtime tested it and it works as intended. It should be used with care -and this should probably be noted somewhere- and preferrably in conjuction with tls-verify or tls-remote and/or password authentication.
I have a couple of improvements in mind (e.g. optionally filtering by certificate subject) and the documentation for the manpage is missing, but I'm posting this early since I will be on vacation for the next week.

Happy holidays :-)

Best regards,
Faidon

cryptoapi.c +58 -1
diff -Nur openvpn-2.1_rc1/cryptoapi.c openvpn-2.1_rc1-void/cryptoapi.c
@@ -48,6 +48,8 @@
 static HINSTANCE crypt32dll = NULL;
 static BOOL WINAPI (*CryptAcquireCertificatePrivateKey) (PCCERT_CONTEXT pCert, DWORD dwFlags,
     void *pvReserved, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec, BOOL *pfCallerFreeProv) = NULL;
+static PCCERT_CONTEXT WINAPI (*CertEnumCertificatesInStore) (HCERTSTORE hCertStore,
+     PCCERT_CONTEXT pPrevCertContext) = NULL;
 #endif
 
 /* Size of an SSL signature: MD5+SHA1 */
@@ -364,7 +366,8 @@
     }
 
     /* cert_context->pbCertEncoded is the cert X509 DER encoded. */
-    cert = d2i_X509(NULL, (unsigned char **) &cd->cert_context->pbCertEncoded,
+    cert = d2i_X509(NULL,
+    		    (const unsigned char **) &cd->cert_context->pbCertEncoded,
 		    cd->cert_context->cbCertEncoded);
     if (cert == NULL) {
 	SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB);
@@ -461,3 +464,57 @@
     }
     return 0;
 }
+
+int SSL_CTX_add_CryptoAPI_certificate_store(SSL_CTX *ssl_ctx, const char *store)
+{
+    HCERTSTORE cs;
+    PCCERT_CONTEXT ctx = NULL;
+    X509 *cert = NULL;
+
+    cs = CertOpenSystemStore(0, store);
+    if (cs == NULL) {
+	CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE);
+	goto err;
+    }
+
+#ifdef __MINGW32_VERSION
+    /* MinGW w32api is incomplete when it comes to CryptoAPI, as per version 3.1
+     * anyway. This is a hack around that problem. */
+    if (crypt32dll == NULL) {
+	crypt32dll = LoadLibrary("crypt32");
+	if (crypt32dll == NULL) {
+	    CRYPTOAPIerr(CRYPTOAPI_F_LOAD_LIBRARY);
+	    goto err;
+	}
+    }
+    if (CertEnumCertificatesInStore == NULL) {
+	CertEnumCertificatesInStore = GetProcAddress(crypt32dll,
+		"CertEnumCertificatesInStore");
+	if (CertEnumCertificatesInStore == NULL) {
+	    CRYPTOAPIerr(CRYPTOAPI_F_GET_PROC_ADDRESS);
+	    goto err;
+	}
+    }
+#endif
+
+    while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
+	cert = d2i_X509(NULL, (const unsigned char **) &ctx->pbCertEncoded,
+			ctx->cbCertEncoded);
+	if (cert == NULL) {
+	    SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB);
+	    goto err;
+	}
+
+	if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+	  goto err;
+	}
+	X509_free(cert);
+    }
+    CertCloseStore(cs, 0);
+    return 1;
+
+  err:
+    if (cert)
+	X509_free(cert);
+    return 0;
+}
cryptoapi.h +1 -0
diff -Nur openvpn-2.1_rc1/cryptoapi.h openvpn-2.1_rc1-void/cryptoapi.h
@@ -2,6 +2,7 @@
 #define _CRYPTOAPI_H_
 
 int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop);
+int SSL_CTX_add_CryptoAPI_certificate_store(SSL_CTX *ssl_ctx, const char *store);
 
 
 #endif /* !_CRYPTOAPI_H_ */
options.c +14 -3
diff -Nur openvpn-2.1_rc1/options.c openvpn-2.1_rc1-void/options.c
@@ -447,6 +447,7 @@
 #ifdef WIN32
   "--cryptoapicert select-string : Load the certificate and private key from the\n"
   "                  Windows Certificate System Store.\n"
+  "--cryptoapicastore : Add Windows Certificate Store Certificate Authorities.\n"
 #endif
   "--tls-cipher l  : A list l of allowable TLS ciphers separated by : (optional).\n"
   "                : Use --show-tls to see a list of supported TLS ciphers.\n"
@@ -1233,6 +1234,7 @@
   SHOW_STR (pkcs12_file);
 #ifdef WIN32
   SHOW_STR (cryptoapi_cert);
+  SHOW_BOOL (cryptoapi_castore);
 #endif
   SHOW_STR (cipher_list);
   SHOW_STR (tls_verify);
@@ -1806,8 +1808,8 @@
 #ifdef WIN32
       if (options->cryptoapi_cert)
 	{
-	  if ((!(options->ca_file)) && (!(options->ca_path)))
-	    msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)");
+	  if ((!(options->ca_file)) && (!(options->ca_path)) && (!(options->cryptoapi_castore)))
+	    msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath) or CryptoAPI CAs (--cryptoapicastore");
           if (options->cert_file)
 	    msg(M_USAGE, "Parameter --cert cannot be used when --cryptoapicert is also specified.");
           if (options->priv_key_file)
@@ -1828,8 +1830,12 @@
         }
       else
         {
-	  if ((!(options->ca_file)) && (!(options->ca_path)))
+	  if ((!(options->ca_file)) && (!(options->ca_path)) && (!(options->cryptoapi_castore)))
+#ifdef WIN32
+	    msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath) or CryptoAPI CAs (--cryptoapicastore");
+#else
 	    msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)");
+#endif
 	  if (pull)
 	    {
 	      const int sum = (options->cert_file != NULL) + (options->priv_key_file != NULL);
@@ -4886,6 +4892,11 @@
       VERIFY_PERMISSION (OPT_P_GENERAL);
       options->cryptoapi_cert = p[1];
     }
+  else if (streq (p[0], "cryptoapicastore"))
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->cryptoapi_castore = true;
+    }
 #endif
   else if (streq (p[0], "key") && p[1])
     {
options.h +1 -0
diff -Nur openvpn-2.1_rc1/options.h openvpn-2.1_rc1-void/options.h
@@ -424,6 +424,7 @@
 
 #ifdef WIN32
   const char *cryptoapi_cert;
+  bool cryptoapi_castore;
 #endif
 
   /* data channel key exchange method */
ssl.c +11 -0
diff -Nur openvpn-2.1_rc1/ssl.c openvpn-2.1_rc1-void/ssl.c
@@ -1276,6 +1276,17 @@
       }
     }
 
+#ifdef WIN32
+      if (options->cryptoapi_castore)
+	{
+	  /* Add CAs from Windows' certification stores to our store */
+	  if (!SSL_CTX_add_CryptoAPI_certificate_store(ctx, "CA"))
+	    msg (M_SSLERR, "Cannot load CA certificates from Microsoft Certificate Store");
+	  if (!SSL_CTX_add_CryptoAPI_certificate_store(ctx, "ROOT"))
+	    msg (M_SSLERR, "Cannot load Root certificates from Microsoft Certificate Store");
+	}
+#endif
+
   /* Enable the use of certificate chains */
   if (using_cert_file)
     {