I hereby release my patches to stunnel for support of PKCS12 files into the
public domain.

---------- Forwarded message ----------
From: Dmitry Bakshaev <dab1...@gmail.com>
Date: 2016-05-18 20:26 GMT+04:00
Subject: PKCS12 support patch
To: stunnel-users@stunnel.org


googling internet about using certificate and keys from PKCS12 file lead to
convert it to PEM.
it requires some additional utilities (openssl not default windows
application) and manual steps to convert.

this patch allow using PKCS12 directly from stunnel.
example configuration:
cert = /home/dab/.certs/my.p12

PKCS12-files detected by file extension (.p12 or .pfx, no case sensetive)
and load specially.
password prompted if needed, empty password also supported.

code based on examples from:
https://groups.google.com/forum/#!topic/mailing.openssl.users/iuBmSqwsIG4
http://openssl-users.openssl.narkive.com/J0bR3cMA/ssl-ctx-use-privatekey-file

patch tested on stunnel working on linux (gentoo: from our overlay
http://bbgentoo.ilb.ru/repos/bbgentoo/bbgentoo_overlay/branches/drafts/net-misc/stunnel/
)
and windows.
--- stunnel-5.32/src/ctx.c.orig	2016-05-03 22:35:03.000000000 +0400
+++ stunnel-5.32/src/ctx.c	2016-05-17 21:17:45.835316702 +0400
@@ -37,6 +37,7 @@
 
 #include "common.h"
 #include "prototypes.h"
+#include <openssl/pkcs12.h>
 
 #ifndef OPENSSL_NO_DH
 DH *dh_params=NULL;
@@ -73,6 +74,7 @@
 #endif /* !defined(OPENSSL_NO_PSK) */
 NOEXPORT int load_cert_file(SERVICE_OPTIONS *);
 NOEXPORT int load_key_file(SERVICE_OPTIONS *);
+NOEXPORT int load_pkcs12_file(SERVICE_OPTIONS *);
 #ifndef OPENSSL_NO_ENGINE
 NOEXPORT int load_cert_engine(SERVICE_OPTIONS *);
 NOEXPORT int load_key_engine(SERVICE_OPTIONS *);
@@ -430,6 +432,7 @@
 
 NOEXPORT int auth_init(SERVICE_OPTIONS *section) {
     int cert_needed=1, key_needed=1;
+    char *ext;
 
 #ifndef OPENSSL_NO_PSK
     if(section->psk_keys) {
@@ -451,6 +454,16 @@
         key_needed=load_key_engine(section);
     }
 #endif
+    /* check file type(extension): is PKCS12? */
+    if (cert_needed && (ext = strrchr(section->cert, '.')) != NULL &&
+        (!strcasecmp(ext+1, "p12") || !strcasecmp(ext+1, "pfx"))) {
+        if (load_pkcs12_file(section)) {
+            return 1; /* FAILED */
+        }
+        /* don't load any PEM files */
+        cert_needed=key_needed=0;
+    }
+
     if(cert_needed && load_cert_file(section))
         return 1; /* FAILED */
     if(key_needed && load_key_file(section))
@@ -617,6 +630,67 @@
     return 0; /* OK */
 }
 
+NOEXPORT int load_pkcs12_file(SERVICE_OPTIONS *section) {
+    int i, reason;
+    UI_DATA ui_data;
+
+    BIO *bio = NULL;
+    PKCS12 *p12 = NULL;
+    X509 * cert = NULL;
+    STACK_OF(X509) * ca = NULL;
+    EVP_PKEY * pkey = NULL;
+    char pass[PEM_BUFSIZE];
+
+    s_log(LOG_INFO, "Loading private key and certificate from file: %s", section->key);
+    if(file_permissions(section->key))
+        return 1; /* FAILED */
+
+    ui_data.section=section; /* setup current section for callbacks */
+
+    if (!(bio = BIO_new_file(section->key, "rb"))) {
+        sslerror("BIO_new_file");
+        return 1; /* FAILED */
+    }
+    if (!(p12 = d2i_PKCS12_bio(bio, NULL))) {
+        sslerror("d2i_PKCS12_bio");
+        return 1; /* FAILED */
+    }
+    BIO_free(bio);
+
+    for(i=0; i<=3; i++) {
+        if(!i && !cache_initialized)
+            continue; /* there is no cached value */
+        /* try empty password */
+        if(i==1 && PKCS12_parse(p12, "", &pkey, &cert, &ca))
+            break;
+        /* try the cached password first */
+        password_cb(pass, PEM_BUFSIZE, 0, (i ? (void *)&ui_data : NULL));
+        if(PKCS12_parse(p12, pass, &pkey, &cert, &ca))
+            break;
+        reason=ERR_GET_REASON(ERR_peek_error());
+        if(i<=2 && reason==PKCS12_R_MAC_VERIFY_FAILURE) {
+            sslerror_queue(); /* dump the error queue */
+            s_log(LOG_ERR, "Wrong pass phrase: retrying");
+            continue;
+        }
+        sslerror("PKCS12_parse");
+        return 1; /* FAILED */
+    }
+    PKCS12_free(p12);
+
+    if (!SSL_CTX_use_certificate(section->ctx, cert)) {
+        sslerror("SSL_CTX_use_certificate");
+        return 1; /* FAILED */
+    }
+    if (!SSL_CTX_use_PrivateKey(section->ctx, pkey)) {
+        sslerror("SSL_CTX_use_PrivateKey");
+        return 1; /* FAILED */
+    }
+
+    s_log(LOG_INFO, "Private key and certificate loaded from file: %s", section->key);
+    return 0; /* OK */
+}
+
 #ifndef OPENSSL_NO_ENGINE
 
 NOEXPORT int load_cert_engine(SERVICE_OPTIONS *section) {
_______________________________________________
stunnel-users mailing list
stunnel-users@stunnel.org
https://www.stunnel.org/cgi-bin/mailman/listinfo/stunnel-users

Reply via email to