Just about working client cert validation
This commit is contained in:
parent
64d34d5d3a
commit
d6d9ca2a04
11
src/accept.c
11
src/accept.c
|
|
@ -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
|
||||
|
||||
|
|
|
|||
31
src/login.c
31
src/login.c
|
|
@ -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
121
src/ssl.c
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
19
src/ssl.h
19
src/ssl.h
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue