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