MINOR: ssl: add pattern and ACLs fetches 'ssl_c_s_dn', 'ssl_c_i_dn', 'ssl_f_s_dn' and 'ssl_c_i_dn'

ssl_c_s_dn : client cert subject DN (string)
ssl_c_i_dn : client cert issuer DN (string)
ssl_f_s_dn : frontend cert subject DN (string)
ssl_f_i_dn : frontend cert issuer DN (string)

Return either the full DN without params, or just the DN entry (first param) or
its specific occurrence (second param).
This commit is contained in:
Emeric Brun 2012-10-17 17:39:35 +02:00 committed by Willy Tarreau
parent a7359fd6dd
commit 8785589ba3
2 changed files with 389 additions and 0 deletions

View File

@ -8374,6 +8374,28 @@ ssl_c_err <integer>
matches the specified value (check man verify for possible values). Note that
error zero means no error was encountered during this verification process.
ssl_c_i_dn <string>
ssl_c_i_dn(entry[,occ]) <string>
If no entry specified, returns true when the incoming connection was made
over an SSL/TLS transport layer, and the full distinguished name of the
issuer of the certificate presented by the client matches the specified
string. Otherwise returns true if the value of the first given entry from
the beginning of the DN matches the specified string. If a positive/negative
occurrence number is specified as the optional second argument, it returns
true if the value of the nth given entry value from the beginning/end of the
DN matches the specified string.
ssl_c_s_dn <string>
ssl_c_s_dn(entry[,occ]) <string>
If no entry specified, returns true when the incoming connection was made
over an SSL/TLS transport layer, and the full distinguished name of the
subject of the certificate presented by the client matches the specified
string. Otherwise returns true if the value of the first given entry from
the beginning of the DN matches the specified string. If a positive/negative
occurrence number is specified as the optional second argument, it returns
true if the value of the nth given entry value from the beginning/end of the
DN matches the specified string.
ssl_c_serial <hexa>
Returns true when the incoming connection was made over an SSL/TLS transport
layer, and the serial of the certificate presented by the client matches
@ -8389,6 +8411,28 @@ ssl_c_version <integer>
layer, and the version of the certificate presented by the client matches
the value.
ssl_f_i_dn <string>
ssl_f_i_dn(entry[,occ]) <string>
If no entry specified, returns true when the incoming connection was made
over an SSL/TLS transport layer, and the full distinguished name of the
issuer of the certificate presented by the frontend matches the specified
string. Otherwise returns true if the value of the first given entry from
the beginning of the DN matches the specified string. If a positive/negative
occurrence number is specified as the optional second argument, it returns
true if the value of the nth given entry value from the beginning/end of the
DN matches the specified string.
ssl_f_s_dn <string>
ssl_f_s_dn(entry[,occ]) <string>
If no entry specified, returns true when the incoming connection was made
over an SSL/TLS transport layer, and the full distinguished name of the
subject of the certificate presented by the frontend matches the specified
string. Otherwise returns true if the value of the first given entry from
the beginning of the DN matches the specified string. If a positive/negative
occurrence number is specified as the optional second argument, it returns
true if the value of the nth given entry value from the beginning/end of the
DN matches the specified string.
ssl_f_serial <hexa>
Returns true when the incoming connection was made over an SSL/TLS transport
layer, and the serial of the certificate presented by the frontend matches
@ -9076,6 +9120,30 @@ The list of currently supported pattern fetch functions is the following :
ssl_c_err Returns the ID of the first error detected during verify of the
client certificate at depth == 0, or 0 if no errors.
ssl_c_i_dn[(entry[,occ])]
If no entry specified, returns the full distinguished name of
the issuer of the certificate presented by the client when
the incoming connection was made over an SSL/TLS transport
layer. Otherwise returns the the value of the first given entry
found from the the beginning of the DN. If a positive/negative
occurrence number is specified as the optional second argument,
it returns the value of the nth given entry found from the
beginning/end of the DN. For instance to retrieve the common
name ssl_c_i_dn(CN) and the second organization unit
ssl_c_i_dn(OU,2).
ssl_c_s_dn[(entry[,occ])]
If no entry specified, returns the full distinguished name of
the subject of the certificate presented by the client when
the incoming connection was made over an SSL/TLS transport
layer. Otherwise returns the the value of the first given entry
found from the the beginning of the DN. If a positive/negative
occurrence number is specified as the optional second argument,
it returns the value of the nth given entry found from the
beginning/end of the DN. For instance to retrieve the common
name ssl_c_s_dn(CN) and the second organization unit
ssl_c_s_dn(OU,2).
ssl_c_serial Returns the serial of the certificate presented by the client
when the incoming connection was made over an SSL/TLS transport
layer.
@ -9089,6 +9157,30 @@ The list of currently supported pattern fetch functions is the following :
when the incoming connection was made over an SSL/TLS transport
layer.
ssl_f_i_dn[(entry[,occ])]
If no entry specified, returns the full distinguished name of
the issuer of the certificate presented by the frontend when
the incoming connection was made over an SSL/TLS transport
layer. Otherwise returns the the value of the first given entry
found from the the beginning of the DN. If a positive/negative
occurrence number is specified as the optional second argument,
it returns the value of the nth given entry found from the
beginning/end of the DN. For instance to retrieve the common
name ssl_f_i_dn(CN) and the second organization unit
ssl_f_i_dn(OU,2).
ssl_f_s_dn[(entry[,occ])]
If no entry specified, returns the full distinguished name of
the subject of the certificate presented by the frontend when
the incoming connection was made over an SSL/TLS transport
layer. Otherwise returns the the value of the first given entry
found from the the beginning of the DN. If a positive/negative
occurrence number is specified as the optional second argument,
it returns the value of the nth given entry found from the
beginning/end of the DN. For instance to retrieve the common
name ssl_f_s_dn(CN) and the second organization unit
ssl_f_s_dn(OU,2).
ssl_f_serial Returns the serial of the certificate presented by the frontend
when the incoming connection was made over an SSL/TLS transport
layer.

View File

@ -1116,6 +1116,98 @@ ssl_sock_get_serial(X509 *crt, struct chunk *out)
return 1;
}
/* Extract an entry from a X509_NAME and copy its value to an output chunk.
* Returns 1 if entry found, 0 if entry not found, or -1 if output not large enough.
*/
static int
ssl_sock_get_dn_entry(X509_NAME *a, const struct chunk *entry, int pos, struct chunk *out)
{
X509_NAME_ENTRY *ne;
int i, j, n;
int cur = 0;
const char *s;
char tmp[128];
out->len = 0;
for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
if (pos < 0)
j = (sk_X509_NAME_ENTRY_num(a->entries)-1) - i;
else
j = i;
ne = sk_X509_NAME_ENTRY_value(a->entries, j);
n = OBJ_obj2nid(ne->object);
if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
i2t_ASN1_OBJECT(tmp, sizeof(tmp), ne->object);
s = tmp;
}
if (chunk_strcasecmp(entry, s) != 0)
continue;
if (pos < 0)
cur--;
else
cur++;
if (cur != pos)
continue;
if (ne->value->length > out->size)
return -1;
memcpy(out->str, ne->value->data, ne->value->length);
out->len = ne->value->length;
return 1;
}
return 0;
}
/* Extract and format full DN from a X509_NAME and copy result into a chunk
* Returns 1 if dn entries exits, 0 if no dn entry found or -1 if output is not large enough.
*/
static int
ssl_sock_get_dn_oneline(X509_NAME *a, struct chunk *out)
{
X509_NAME_ENTRY *ne;
int i, n, ln;
int l = 0;
const char *s;
char *p;
char tmp[128];
out->len = 0;
p = out->str;
for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
ne = sk_X509_NAME_ENTRY_value(a->entries, i);
n = OBJ_obj2nid(ne->object);
if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
i2t_ASN1_OBJECT(tmp, sizeof(tmp), ne->object);
s = tmp;
}
ln = strlen(s);
l += 1 + ln + 1 + ne->value->length;
if (l > out->size)
return -1;
out->len = l;
*(p++)='/';
memcpy(p, s, ln);
p += ln;
*(p++)='=';
memcpy(p, ne->value->data, ne->value->length);
p += ne->value->length;
}
if (!out->len)
return 0;
return 1;
}
/***** Below are some sample fetching functions for ACL/patterns *****/
/* boolean, returns true if client cert was present */
@ -1173,6 +1265,107 @@ out:
return ret;
}
/* str, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. */
static int
smp_fetch_ssl_c_i_dn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp)
{
X509 *crt = NULL;
X509_NAME *name;
int ret = 0;
struct chunk *smp_trash;
if (!l4 || l4->si[0].conn.xprt != &ssl_sock)
return 0;
if (!(l4->si[0].conn.flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE;
return 0;
}
/* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn.xprt_ctx);
if (!crt)
goto out;
name = X509_get_issuer_name(crt);
if (!name)
goto out;
smp_trash = sample_get_trash_chunk();
if (args && args[0].type == ARGT_STR) {
int pos = 1;
if (args[1].type == ARGT_SINT)
pos = args[1].data.sint;
else if (args[1].type == ARGT_UINT)
pos =(int)args[1].data.uint;
if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
goto out;
}
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
goto out;
smp->type = SMP_T_STR;
smp->data.str = *smp_trash;
ret = 1;
out:
if (crt)
X509_free(crt);
return ret;
}
/* str, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. */
static int
smp_fetch_ssl_c_s_dn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp)
{
X509 *crt = NULL;
X509_NAME *name;
int ret = 0;
struct chunk *smp_trash;
if (!l4 || l4->si[0].conn.xprt != &ssl_sock)
return 0;
if (!(l4->si[0].conn.flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE;
return 0;
}
/* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn.xprt_ctx);
if (!crt)
goto out;
name = X509_get_subject_name(crt);
if (!name)
goto out;
smp_trash = sample_get_trash_chunk();
if (args && args[0].type == ARGT_STR) {
int pos = 1;
if (args[1].type == ARGT_SINT)
pos = args[1].data.sint;
else if (args[1].type == ARGT_UINT)
pos =(int)args[1].data.uint;
if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
goto out;
}
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
goto out;
smp->type = SMP_T_STR;
smp->data.str = *smp_trash;
ret = 1;
out:
if (crt)
X509_free(crt);
return ret;
}
/* integer, returns the client certificate version */
static int
smp_fetch_ssl_c_version(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
@ -1284,6 +1477,102 @@ smp_fetch_ssl_f_version(struct proxy *px, struct session *l4, void *l7, unsigned
return 1;
}
/* str, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. */
static int
smp_fetch_ssl_f_i_dn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp)
{
X509 *crt = NULL;
X509_NAME *name;
int ret = 0;
struct chunk *smp_trash;
if (!l4 || l4->si[0].conn.xprt != &ssl_sock)
return 0;
if (!(l4->si[0].conn.flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE;
return 0;
}
crt = SSL_get_certificate(l4->si[0].conn.xprt_ctx);
if (!crt)
goto out;
name = X509_get_issuer_name(crt);
if (!name)
goto out;
smp_trash = sample_get_trash_chunk();
if (args && args[0].type == ARGT_STR) {
int pos = 1;
if (args[1].type == ARGT_SINT)
pos = args[1].data.sint;
else if (args[1].type == ARGT_UINT)
pos =(int)args[1].data.uint;
if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
goto out;
}
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
goto out;
smp->type = SMP_T_STR;
smp->data.str = *smp_trash;
ret = 1;
out:
return ret;
}
/* str, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. */
static int
smp_fetch_ssl_f_s_dn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp)
{
X509 *crt = NULL;
X509_NAME *name;
int ret = 0;
struct chunk *smp_trash;
if (!l4 || l4->si[0].conn.xprt != &ssl_sock)
return 0;
if (!(l4->si[0].conn.flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE;
return 0;
}
crt = SSL_get_certificate(l4->si[0].conn.xprt_ctx);
if (!crt)
goto out;
name = X509_get_subject_name(crt);
if (!name)
goto out;
smp_trash = sample_get_trash_chunk();
if (args && args[0].type == ARGT_STR) {
int pos = 1;
if (args[1].type == ARGT_SINT)
pos = args[1].data.sint;
else if (args[1].type == ARGT_UINT)
pos =(int)args[1].data.uint;
if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
goto out;
}
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
goto out;
smp->type = SMP_T_STR;
smp->data.str = *smp_trash;
ret = 1;
out:
return ret;
}
static int
smp_fetch_ssl_fc_cipher(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp)
@ -1998,9 +2287,13 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{
{ "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_c_i_dn", smp_fetch_ssl_c_i_dn, ARG2(0,STR,SINT), NULL, SMP_T_STR, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_c_s_dn", smp_fetch_ssl_c_s_dn, ARG2(0,STR,SINT), NULL, SMP_T_STR, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_c_serial", smp_fetch_ssl_c_serial, 0, NULL, SMP_T_BIN, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_c_version", smp_fetch_ssl_c_version, 0, NULL, SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_f_i_dn", smp_fetch_ssl_f_i_dn, ARG2(0,STR,SINT), NULL, SMP_T_STR, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_f_s_dn", smp_fetch_ssl_f_s_dn, ARG2(0,STR,SINT), NULL, SMP_T_STR, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_f_serial", smp_fetch_ssl_f_serial, 0, NULL, SMP_T_BIN, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_f_version", smp_fetch_ssl_f_version, 0, NULL, SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_CAP_REQ|SMP_CAP_RES },
@ -2025,9 +2318,13 @@ static struct acl_kw_list acl_kws = {{ },{
{ "ssl_c_ca_err", acl_parse_int, smp_fetch_ssl_c_ca_err, acl_match_int, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_c_ca_err_depth", acl_parse_int, smp_fetch_ssl_c_ca_err_depth, acl_match_int, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_c_err", acl_parse_int, smp_fetch_ssl_c_err, acl_match_int, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_c_i_dn", acl_parse_str, smp_fetch_ssl_c_i_dn, acl_match_str, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, ARG2(0,STR,SINT) },
{ "ssl_c_s_dn", acl_parse_str, smp_fetch_ssl_c_s_dn, acl_match_str, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, ARG2(0,STR,SINT) },
{ "ssl_c_serial", acl_parse_bin, smp_fetch_ssl_c_serial, acl_match_bin, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_c_verify", acl_parse_int, smp_fetch_ssl_c_verify, acl_match_int, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_c_version", acl_parse_int, smp_fetch_ssl_c_version, acl_match_int, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_f_i_dn", acl_parse_str, smp_fetch_ssl_f_i_dn, acl_match_str, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, ARG2(0,STR,SINT) },
{ "ssl_f_s_dn", acl_parse_str, smp_fetch_ssl_f_s_dn, acl_match_str, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, ARG2(0,STR,SINT) },
{ "ssl_f_serial", acl_parse_bin, smp_fetch_ssl_f_serial, acl_match_bin, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_f_version", acl_parse_int, smp_fetch_ssl_f_version, acl_match_int, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_fc", acl_parse_int, smp_fetch_ssl_fc, acl_match_nothing, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },