Hello,

for our current use-case we needed to add functionality to stunnel and 
therefore have made few patches. We distribute these patches with our software 
and were wondering what do you think about including them directly in stunnel.

Firstly, we need peer certificate fingerprints in MD5, SHA1, SHA224, SHA256, 
SHA384 and SHA512. Patched stunnel exports all these in separate variables 
"SSL_CLIENT_*".

Secondly, we could need subjectAltName values. Patched stunnel exports these in 
"SSL_CLIENT_SAN", but only rfc822Name, iPAddress and dNSName as we need only 
these. It could easily be expanded to all the values.

Lastly, we required verification as if we first used verify = 2 and after 
failing trying verify = 4 (verify = 3 is technically verify = 2 AND verify = 4, 
if I am not wrong, and we need verify = 2 OR verify = 4). For this purpose my 
patch adds new verify = 5 option.

I want to say that we did not just make all these requirements up, but we want 
to conform to RFCs describing NETCONF over TLS and its configuration. All the 
patches are included so you can go through them. Thank you.

Kind regards,
Michal Vasko
--- ./client(orig).c	2014-04-12 20:55:57.000000000 +0200
+++ ./client.c	2014-08-04 14:16:38.824560757 +0200
@@ -1075,6 +1075,11 @@
     char *name, host[40];
     int fd[2], pid;
     X509 *peer;
+	unsigned char *digest;
+	unsigned int dig_len, i;
+	STACK_OF(GENERAL_NAME) *san_names;
+	GENERAL_NAME *san_name;
+	ASN1_OCTET_STRING *ip;
 #ifdef HAVE_PTHREAD_SIGMASK
     sigset_t newmask;
 #endif
@@ -1135,6 +1140,85 @@
                 name=X509_NAME_oneline(X509_get_issuer_name(peer), NULL, 0);
                 safestring(name);
                 putenv(str_printf("SSL_CLIENT_I_DN=%s", name));
+
+				/* calculate peer fingerprints using MD5 and SHA algorithms */
+				dig_len = 64;
+				digest = malloc(dig_len);
+				X509_digest(peer, EVP_md5(), digest, &dig_len);
+				name = str_printf("SSL_CLIENT_MD5=%02x:%02x:%02x:%02x", digest[0], digest[1], digest[2], digest[3]);
+				for (i = 4; i < dig_len; i += 4) {
+					name = str_printf("%s:%02x:%02x:%02x:%02x", name, digest[i], digest[i+1], digest[i+2], digest[i+3]);
+				}
+				putenv(name);
+
+				X509_digest(peer, EVP_sha1(), digest, &dig_len);
+				name = str_printf("SSL_CLIENT_SHA1=%02x:%02x:%02x:%02x", digest[0], digest[1], digest[2], digest[3]);
+				for (i = 4; i < dig_len; i += 4) {
+					name = str_printf("%s:%02x:%02x:%02x:%02x", name, digest[i], digest[i+1], digest[i+2], digest[i+3]);
+				}
+				putenv(name);
+
+				X509_digest(peer, EVP_sha224(), digest, &dig_len);
+				name = str_printf("SSL_CLIENT_SHA224=%02x:%02x:%02x:%02x", digest[0], digest[1], digest[2], digest[3]);
+				for (i = 4; i < dig_len; i += 4) {
+					name = str_printf("%s:%02x:%02x:%02x:%02x", name, digest[i], digest[i+1], digest[i+2], digest[i+3]);
+				}
+				putenv(name);
+
+				X509_digest(peer, EVP_sha256(), digest, &dig_len);
+				name = str_printf("SSL_CLIENT_SHA256=%02x:%02x:%02x:%02x", digest[0], digest[1], digest[2], digest[3]);
+				for (i = 4; i < dig_len; i += 4) {
+					name = str_printf("%s:%02x:%02x:%02x:%02x", name, digest[i], digest[i+1], digest[i+2], digest[i+3]);
+				}
+				putenv(name);
+
+				X509_digest(peer, EVP_sha384(), digest, &dig_len);
+				name = str_printf("SSL_CLIENT_SHA384=%02x:%02x:%02x:%02x", digest[0], digest[1], digest[2], digest[3]);
+				for (i = 4; i < dig_len; i += 4) {
+					name = str_printf("%s:%02x:%02x:%02x:%02x", name, digest[i], digest[i+1], digest[i+2], digest[i+3]);
+				}
+				putenv(name);
+
+				X509_digest(peer, EVP_sha512(), digest, &dig_len);
+				name = str_printf("SSL_CLIENT_SHA512=%02x:%02x:%02x:%02x", digest[0], digest[1], digest[2], digest[3]);
+				for (i = 4; i < dig_len; i += 4) {
+					name = str_printf("%s:%02x:%02x:%02x:%02x", name, digest[i], digest[i+1], digest[i+2], digest[i+3]);
+				}
+				putenv(name);
+				free(digest);
+
+				/* retrieve subjectAltName's rfc822Name (email), dNSName and iPAddress values */
+				san_names = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL);
+				if (san_names != NULL) {
+					name = str_printf("SSL_CLIENT_SAN=");
+					for (i = 0; i < (unsigned) sk_GENERAL_NAME_num(san_names); ++i) {
+						san_name = sk_GENERAL_NAME_value(san_names, i);
+						if (san_name->type == GEN_EMAIL || san_name->type == GEN_DNS || san_name->type == GEN_IPADD) {
+							if (san_name->type == GEN_EMAIL) {
+								name = str_printf("%s/EMAIL=%s", name, (char*) ASN1_STRING_data(san_name->d.rfc822Name));
+							}
+							if (san_name->type == GEN_DNS) {
+								name = str_printf("%s/DNS=%s", name, (char*) ASN1_STRING_data(san_name->d.dNSName));
+							}
+							if (san_name->type == GEN_IPADD) {
+								ip = san_name->d.iPAddress;
+								if (ip->length == 4) {
+									name = str_printf("%s/IP=%d.%d.%d.%d", name, ip->data[0], ip->data[1], ip->data[2], ip->data[3]);
+								} else if (ip->length == 16) {
+									name = str_printf("%s/IP=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+										name, ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
+										ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11], ip->data[12],
+										ip->data[13], ip->data[14], ip->data[15]);
+								}
+							}
+						}
+					}
+					if (strlen(name) > 15) {
+						putenv(name);
+					}
+					sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+				}
+
                 X509_free(peer);
             }
         }
--- ./verify(orig).c	2014-04-12 10:28:44.000000000 +0200
+++ ./verify.c	2014-08-01 10:30:03.633181215 +0200
@@ -250,11 +250,13 @@
         SSL_get_ex_data_X509_STORE_CTX_idx());
     CLI *c=SSL_get_ex_data(ssl, cli_index);
     int depth=X509_STORE_CTX_get_error_depth(callback_ctx);
+	static int ca_verify_ok = 1;
 
     if(!preverify_ok) {
         /* remote site specified a certificate, but it's not correct */
         if(c->opt->verify_level>=4 && depth>0) {
             s_log(LOG_INFO, "CERT: Invalid CA certificate ignored");
+			ca_verify_ok = 0;
             return 1; /* success */
         } else {
             s_log(LOG_WARNING, "CERT: Verification error: %s",
@@ -263,9 +265,13 @@
             return 0; /* fail */
         }
     }
-    if(c->opt->verify_level>=3 && depth==0)
-        if(!cert_check_local(callback_ctx))
+	if((!ca_verify_ok && c->opt->verify_level>=5 && depth==0) || (c->opt->verify_level>=3 && c->opt->verify_level<=4 && depth==0)) {
+        if(!cert_check_local(callback_ctx)) {
+			ca_verify_ok = 1;
             return 0; /* fail */
+		} else
+			ca_verify_ok = 1;
+	}
     return 1; /* success */
 }
 
--- ./options(orig).c	2014-06-09 01:18:08.000000000 +0200
+++ ./options.c	2014-08-01 10:56:35.837036478 +0200
@@ -2085,7 +2085,7 @@
         section->verify_level=strtol(arg, &tmpstr, 10);
         if(tmpstr==arg || *tmpstr) /* not a number */
             return "Bad verify level";
-        if(section->verify_level<0 || section->verify_level>4)
+        if(section->verify_level<0 || section->verify_level>5)
             return "Bad verify level";
         return NULL; /* OK */
     case CMD_END:
@@ -2108,6 +2108,8 @@
             "%25slevel 3 - verify peer with locally installed cert", "");
         s_log(LOG_NOTICE,
             "%25slevel 4 - ignore CA chain and only verify peer cert", "");
+		s_log(LOG_NOTICE,
+			"%25slevel 5 - verify peer with CA chain, on fail check with local cert", "");
         break;
     }
 
_______________________________________________
stunnel-users mailing list
[email protected]
https://www.stunnel.org/cgi-bin/mailman/listinfo/stunnel-users

Reply via email to