Just about working client cert validation

This commit is contained in:
Heikki Hannikainen 2013-03-04 23:38:04 +02:00
parent 64d34d5d3a
commit d6d9ca2a04
4 changed files with 171 additions and 11 deletions

View File

@ -322,7 +322,16 @@ static int open_listener(struct listen_config_t *lc)
return -1;
}
hlog(LOG_INFO, "SSL initialized for '%s': %s", lc->name, l->addr_s);
/* optional client cert validation */
if (lc->cafile) {
if (ssl_ca_certificate(l->ssl, lc->cafile, 2)) {
hlog(LOG_ERR, "Failed to load trusted SSL CA certificates for '%s*': %s", lc->name, l->addr_s);
listener_free(l);
return -1;
}
}
hlog(LOG_INFO, "SSL initialized for '%s': %s%s", lc->name, l->addr_s, (lc->cafile) ? " (client validation enabled)" : "");
}
#endif

View File

@ -21,6 +21,7 @@
#include "filter.h"
#include "clientlist.h"
#include "parse_qc.h"
#include "ssl.h"
/* a static list of usernames which are not allowed to log in */
static const char *disallow_login_usernames[] = {
@ -237,6 +238,7 @@ int login_handler(struct worker_t *self, struct client_t *c, int l4proto, char *
goto failed_login;
}
/* ok, it's somewhat valid, write it down */
strncpy(c->username, username, sizeof(c->username));
c->username[sizeof(c->username)-1] = 0;
c->username_len = strlen(c->username);
@ -257,6 +259,25 @@ int login_handler(struct worker_t *self, struct client_t *c, int l4proto, char *
goto failed_login;
}
/* if SSL client cert verification is enabled, check it */
int ssl_validated = 0;
#ifdef USE_SSL
if (c->ssl_con && c->ssl_con->validate) {
hlog(LOG_DEBUG, "%s/%s: login: doing SSL client cert validation", c->addr_rem, c->username);
int ssl_res = ssl_validate_client_cert(c);
if (ssl_res) {
hlog(LOG_WARNING, "%s/%s: SSL client cert validation failed", c->addr_rem, c->username);
rc = client_printf(self, c, "# Client certificate validation failed\r\n");
c->failed_cmds = 10; /* bail out right away for a HTTP client */
goto failed_login;
}
hlog(LOG_INFO, "%s/%s: Login validated using SSL client certificate");
c->validated = 1;
ssl_validated = 1;
}
#endif
int given_passcode = -1;
for (i = 2; i < argc; i++) {
@ -266,10 +287,12 @@ int login_handler(struct worker_t *self, struct client_t *c, int l4proto, char *
break;
}
given_passcode = atoi(argv[i]);
if (given_passcode >= 0)
if (given_passcode == aprs_passcode(c->username))
c->validated = 1;
if (!ssl_validated) {
given_passcode = atoi(argv[i]);
if (given_passcode >= 0)
if (given_passcode == aprs_passcode(c->username))
c->validated = 1;
}
} else if (strcasecmp(argv[i], "vers") == 0) {
/* Collect application name and version separately.
* Some clients only give out application name but

121
src/ssl.c
View File

@ -330,8 +330,91 @@ int ssl_certificate(struct ssl_t *ssl, const char *certfile, const char *keyfile
return 0;
}
static int ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
{
hlog(LOG_DEBUG, "ssl_verify_callback, ok: %d", ok);
#if (NGX_DEBUG)
char *subject, *issuer;
int err, depth;
X509 *cert;
X509_NAME *sname, *iname;
ngx_connection_t *c;
ngx_ssl_conn_t *ssl_conn;
ssl_conn = X509_STORE_CTX_get_ex_data(x509_store,
SSL_get_ex_data_X509_STORE_CTX_idx());
c = ngx_ssl_get_connection(ssl_conn);
cert = X509_STORE_CTX_get_current_cert(x509_store);
err = X509_STORE_CTX_get_error(x509_store);
depth = X509_STORE_CTX_get_error_depth(x509_store);
sname = X509_get_subject_name(cert);
subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)";
iname = X509_get_issuer_name(cert);
issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)";
ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
"verify:%d, error:%d, depth:%d, "
"subject:\"%s\",issuer: \"%s\"",
ok, err, depth, subject, issuer);
if (sname) {
OPENSSL_free(subject);
}
if (iname) {
OPENSSL_free(issuer);
}
#endif
return 1;
}
/*
* Create a connect */
* Load trusted CA certs
*/
int ssl_ca_certificate(struct ssl_t *ssl, const char *cafile, int depth)
{
STACK_OF(X509_NAME) *list;
SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ssl_verify_callback);
SSL_CTX_set_verify_depth(ssl->ctx, depth);
if (SSL_CTX_load_verify_locations(ssl->ctx, cafile, NULL) == 0) {
hlog(LOG_ERR, "SSL_CTX_load_verify_locations(\"%s\") failed", cafile);
return -1;
}
list = SSL_load_client_CA_file(cafile);
if (list == NULL) {
hlog(LOG_ERR, "SSL_load_client_CA_file(\"%s\") failed", cafile);
return -1;
}
/*
* before 0.9.7h and 0.9.8 SSL_load_client_CA_file()
* always leaved an error in the error queue
*/
ERR_clear_error();
SSL_CTX_set_client_CA_list(ssl->ctx, list);
ssl->validate = 1;
return 0;
}
/*
* Create a connect
*/
int ssl_create_connection(struct ssl_t *ssl, struct client_t *c, int i_am_client)
{
@ -363,11 +446,47 @@ int ssl_create_connection(struct ssl_t *ssl, struct client_t *c, int i_am_client
return -1;
}
sc->validate = ssl->validate;
c->ssl_con = sc;
return 0;
}
/*
* Validate client certificate
*/
int ssl_validate_client_cert(struct client_t *c)
{
long rc;
X509 *cert;
rc = SSL_get_verify_result(c->ssl_con->connection);
if (rc != X509_V_OK) {
hlog(LOG_INFO, "%s/%s: client SSL certificate verify error: (%l:%s)", c->addr_rem, c->username, rc, X509_verify_cert_error_string(rc));
return -1;
}
cert = SSL_get_peer_certificate(c->ssl_con->connection);
if (cert == NULL) {
hlog(LOG_INFO, "%s/%s: client sent no required SSL certificate", c->addr_rem, c->username);
return -1;
}
hlog(LOG_INFO, "%s/%s: Login validated using SSL client certificate");
X509_free(cert);
return 0;
}
/*
* Write data to an SSL socket
*/
int ssl_write(struct worker_t *self, struct client_t *c)
{

View File

@ -21,6 +21,8 @@ struct worker_t;
struct ssl_t {
SSL_CTX *ctx;
unsigned validate;
};
struct ssl_connection_t {
@ -34,11 +36,14 @@ struct ssl_connection_t {
ngx_event_handler_pt saved_read_handler;
ngx_event_handler_pt saved_write_handler;
*/
unsigned handshaked:1;
unsigned renegotiation:1;
unsigned buffer:1;
unsigned no_wait_shutdown:1;
unsigned no_send_shutdown:1;
unsigned handshaked:1;
unsigned renegotiation:1;
unsigned buffer:1;
unsigned no_wait_shutdown:1;
unsigned no_send_shutdown:1;
unsigned validate;
};
#define NGX_SSL_SSLv2 0x0002
@ -64,10 +69,14 @@ extern void ssl_free(struct ssl_t *ssl);
/* create context for listener, load certs */
extern int ssl_create(struct ssl_t *ssl, void *data);
extern int ssl_certificate(struct ssl_t *ssl, const char *certfile, const char *keyfile);
extern int ssl_ca_certificate(struct ssl_t *ssl, const char *cafile, int depth);
/* create / free connection */
extern int ssl_create_connection(struct ssl_t *ssl, struct client_t *c, int i_am_client);
/* validate a client certificate */
extern int ssl_validate_client_cert(struct client_t *c);
extern int ssl_write(struct worker_t *self, struct client_t *c);
extern int ssl_writeable(struct worker_t *self, struct client_t *c);
extern int ssl_readable(struct worker_t *self, struct client_t *c);