Skip to content

Commit

Permalink
Kill OPENCONNECT_X509, let certain functions only operate on peer_cert
Browse files Browse the repository at this point in the history
This makes the certificate handling a whole lot saner.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Nov 3, 2014
1 parent be40969 commit 1cc5b5c
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 126 deletions.
72 changes: 42 additions & 30 deletions gnutls.c
Expand Up @@ -1648,43 +1648,51 @@ static int get_cert_fingerprint(struct openconnect_info *vpninfo,
}

int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
OPENCONNECT_X509 *cert, char *buf)
void *cert, char *buf)
{
return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
}

int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
OPENCONNECT_X509 *cert, char *buf)
const char *openconnect_get_peer_cert_hash(struct openconnect_info *vpninfo)
{
return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_SHA1, buf);
if (!vpninfo->peer_cert_hash) {
char buf[41];

if (get_cert_fingerprint(vpninfo, vpninfo->peer_cert,
GNUTLS_DIG_SHA1, buf))
return NULL;

vpninfo->peer_cert_hash = strdup(buf);
}
return vpninfo->peer_cert_hash;
}

char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
OPENCONNECT_X509 *cert)
char *openconnect_get_peer_cert_details(struct openconnect_info *vpninfo)
{
gnutls_datum_t buf;

if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &buf))
if (gnutls_x509_crt_print(vpninfo->peer_cert, GNUTLS_CRT_PRINT_FULL, &buf))
return NULL;

return (char *)buf.data;
}

int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
OPENCONNECT_X509 *cert, unsigned char **buf)
int openconnect_get_peer_cert_DER(struct openconnect_info *vpninfo,
unsigned char **buf)
{
size_t l = 0;
unsigned char *ret = NULL;

if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l) !=
GNUTLS_E_SHORT_MEMORY_BUFFER)
if (gnutls_x509_crt_export(vpninfo->peer_cert, GNUTLS_X509_FMT_DER,
ret, &l) != GNUTLS_E_SHORT_MEMORY_BUFFER)
return -EIO;

ret = gnutls_malloc(l);
if (!ret)
return -ENOMEM;

if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l)) {
if (gnutls_x509_crt_export(vpninfo->peer_cert, GNUTLS_X509_FMT_DER,
ret, &l)) {
gnutls_free(ret);
return -EIO;
}
Expand All @@ -1705,7 +1713,7 @@ static int verify_peer(gnutls_session_t session)
gnutls_x509_crt_t cert;
unsigned int status, cert_list_size;
const char *reason = NULL;
int err;
int err = 0;

if (vpninfo->peer_cert) {
gnutls_x509_crt_deinit(vpninfo->peer_cert);
Expand All @@ -1718,6 +1726,19 @@ static int verify_peer(gnutls_session_t session)
return GNUTLS_E_CERTIFICATE_ERROR;
}

err = gnutls_x509_crt_init(&cert);
if (err) {
vpn_progress(vpninfo, PRG_ERR, _("Error initialising X509 cert structure\n"));
return GNUTLS_E_CERTIFICATE_ERROR;
}

err = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
if (err) {
vpn_progress(vpninfo, PRG_ERR, _("Error importing server's cert\n"));
gnutls_x509_crt_deinit(cert);
return GNUTLS_E_CERTIFICATE_ERROR;
}

if (vpninfo->servercert) {
unsigned char sha1bin[SHA1_SIZE];
char fingerprint[(SHA1_SIZE * 2) + 1];
Expand All @@ -1737,7 +1758,7 @@ static int verify_peer(gnutls_session_t session)
_("Server SSL certificate didn't match: %s\n"), fingerprint);
return GNUTLS_E_CERTIFICATE_ERROR;
}
return 0;
goto done;
}

err = gnutls_certificate_verify_peers2(session, &status);
Expand All @@ -1764,19 +1785,6 @@ static int verify_peer(gnutls_session_t session)
why we don't just set a bit for that too. */
reason = _("signature verification failed");

err = gnutls_x509_crt_init(&cert);
if (err) {
vpn_progress(vpninfo, PRG_ERR, _("Error initialising X509 cert structure\n"));
return GNUTLS_E_CERTIFICATE_ERROR;
}

err = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
if (err) {
vpn_progress(vpninfo, PRG_ERR, _("Error importing server's cert\n"));
gnutls_x509_crt_deinit(cert);
return GNUTLS_E_CERTIFICATE_ERROR;
}

if (reason)
goto done;

Expand Down Expand Up @@ -1826,20 +1834,21 @@ static int verify_peer(gnutls_session_t session)
reason = _("certificate does not match hostname");
}
done:
vpninfo->peer_cert = cert;
free(vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = 0;

if (reason) {
vpn_progress(vpninfo, PRG_INFO,
_("Server certificate verify failed: %s\n"),
reason);
if (vpninfo->validate_peer_cert)
err = vpninfo->validate_peer_cert(vpninfo->cbdata,
cert,
reason) ? GNUTLS_E_CERTIFICATE_ERROR : 0;
else
err = GNUTLS_E_CERTIFICATE_ERROR;
}

vpninfo->peer_cert = cert;

return err;
}

Expand Down Expand Up @@ -2086,6 +2095,9 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
gnutls_x509_crt_deinit(vpninfo->peer_cert);
vpninfo->peer_cert = NULL;
}
free(vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = NULL;

if (vpninfo->https_sess) {
gnutls_deinit(vpninfo->https_sess);
vpninfo->https_sess = NULL;
Expand Down
28 changes: 11 additions & 17 deletions jni.c
Expand Up @@ -32,7 +32,6 @@ struct libctx {
jobject jobj;
jobject async_lock;
struct openconnect_info *vpninfo;
OPENCONNECT_X509 *cert;
int cmd_fd;
int loglevel;
};
Expand Down Expand Up @@ -195,7 +194,7 @@ static int add_string_pair(struct libctx *ctx, jclass jcls, jobject jobj,
return 0;
}

static int validate_peer_cert_cb(void *privdata, OPENCONNECT_X509 *cert, const char *reason)
static int validate_peer_cert_cb(void *privdata, const char *reason)
{
struct libctx *ctx = privdata;
jstring jreason;
Expand All @@ -209,7 +208,6 @@ static int validate_peer_cert_cb(void *privdata, OPENCONNECT_X509 *cert, const c
if (!jreason)
goto out;

ctx->cert = cert;
mid = get_obj_mid(ctx, ctx->jobj, "onValidatePeerCert", "(Ljava/lang/String;)I");
if (mid)
ret = (*ctx->jenv)->CallIntMethod(ctx->jenv, ctx->jobj, mid, jreason);
Expand Down Expand Up @@ -685,30 +683,26 @@ JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_obtainCo
JNIEnv *jenv, jobject jobj)
{
struct libctx *ctx = getctx(jenv, jobj);
int ret;

if (!ctx)
return 0;
ctx->cert = NULL;
ret = openconnect_obtain_cookie(ctx->vpninfo);
if (ret == 0)
ctx->cert = openconnect_get_peer_cert(ctx->vpninfo);
return ret;
return openconnect_obtain_cookie(ctx->vpninfo);
}

/* special handling: caller-allocated buffer */
JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getCertSHA1(
JNIEnv *jenv, jobject jobj)
{
struct libctx *ctx = getctx(jenv, jobj);
char buf[41];
const char *hash;
jstring jresult = NULL;

if (!ctx || !ctx->cert)
if (!ctx)
return NULL;
if (openconnect_get_cert_sha1(ctx->vpninfo, ctx->cert, buf))
hash = openconnect_get_peer_cert_hash(ctx->vpninfo);
if (!hash)
return NULL;
jresult = dup_to_jstring(ctx->jenv, buf);
jresult = dup_to_jstring(ctx->jenv, hash);
if (!jresult)
OOM(ctx->jenv);
return jresult;
Expand All @@ -722,9 +716,9 @@ JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getCe
char *buf = NULL;
jstring jresult = NULL;

if (!ctx || !ctx->cert)
if (!ctx)
return NULL;
buf = openconnect_get_cert_details(ctx->vpninfo, ctx->cert);
buf = openconnect_get_peer_cert_details(ctx->vpninfo);
if (!buf)
return NULL;

Expand All @@ -745,9 +739,9 @@ JNIEXPORT jbyteArray JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_ge
int ret;
jbyteArray jresult = NULL;

if (!ctx || !ctx->cert)
if (!ctx)
return NULL;
ret = openconnect_get_cert_DER(ctx->vpninfo, ctx->cert, &buf);
ret = openconnect_get_peer_cert_DER(ctx->vpninfo, &buf);
if (ret < 0)
return NULL;

Expand Down
15 changes: 5 additions & 10 deletions libopenconnect.map.in
@@ -1,12 +1,11 @@
OPENCONNECT_4.0 {
OPENCONNECT_5.0 {
global:
openconnect_free_cert_info;
openconnect_set_option_value;
openconnect_clear_cookie;
openconnect_get_cert_sha1;
openconnect_get_peer_cert_hash;
openconnect_get_cookie;
openconnect_get_hostname;
openconnect_get_peer_cert;
openconnect_get_port;
openconnect_get_urlpath;
openconnect_get_version;
Expand All @@ -25,8 +24,8 @@ OPENCONNECT_4.0 {
openconnect_vpninfo_free;
openconnect_set_cert_expiry_warning;
openconnect_set_cancel_fd;
openconnect_get_cert_details;
openconnect_get_cert_DER;
openconnect_get_peer_cert_details;
openconnect_get_peer_cert_DER;
openconnect_init_ssl;
openconnect_has_tss_blob_support;
openconnect_has_pkcs11_support;
Expand Down Expand Up @@ -54,15 +53,11 @@ OPENCONNECT_4.0 {
openconnect_set_dpd;
openconnect_set_proxy_auth;
openconnect_set_token_callbacks;
};

OPENCONNECT_4.1 {
global:
openconnect_set_system_trust;
openconnect_get_dtls_cipher;
openconnect_get_cstp_cipher;
openconnect_set_csd_environ;
} OPENCONNECT_4.0;
};


OPENCONNECT_PRIVATE {
Expand Down
6 changes: 1 addition & 5 deletions library.c
Expand Up @@ -236,6 +236,7 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
#endif
vpninfo->peer_cert = NULL;
}
free(vpninfo->peer_cert_hash);
free(vpninfo->localname);
free(vpninfo->useragent);
free(vpninfo->authgroup);
Expand Down Expand Up @@ -394,11 +395,6 @@ int openconnect_set_client_cert(struct openconnect_info *vpninfo,
return 0;
}

OPENCONNECT_X509 *openconnect_get_peer_cert(struct openconnect_info *vpninfo)
{
return vpninfo->peer_cert;
}

int openconnect_get_port(struct openconnect_info *vpninfo)
{
return vpninfo->port;
Expand Down
25 changes: 8 additions & 17 deletions main.c
Expand Up @@ -66,9 +66,7 @@ static int write_new_config(void *_vpninfo,
const char *buf, int buflen);
static void __attribute__ ((format(printf, 3, 4)))
write_progress(void *_vpninfo, int level, const char *fmt, ...);
static int validate_peer_cert(void *_vpninfo,
OPENCONNECT_X509 *peer_cert,
const char *reason);
static int validate_peer_cert(void *_vpninfo, const char *reason);
static int process_auth_form_cb(void *_vpninfo,
struct oc_auth_form *form);
static void init_token(struct openconnect_info *vpninfo,
Expand Down Expand Up @@ -1333,11 +1331,8 @@ int main(int argc, char **argv)
/* --authenticate */
printf("COOKIE='%s'\n", vpninfo->cookie);
printf("HOST='%s'\n", openconnect_get_hostname(vpninfo));
if (vpninfo->peer_cert) {
char buf[41] = {0, };
openconnect_get_cert_sha1(vpninfo, vpninfo->peer_cert, buf);
printf("FINGERPRINT='%s'\n", buf);
}
printf("FINGERPRINT='%s'\n",
openconnect_get_peer_cert_hash(vpninfo));
openconnect_vpninfo_free(vpninfo);
exit(0);
} else if (cookieonly) {
Expand Down Expand Up @@ -1531,20 +1526,16 @@ struct accepted_cert {
char host[0];
} *accepted_certs;

static int validate_peer_cert(void *_vpninfo, OPENCONNECT_X509 *peer_cert,
const char *reason)
static int validate_peer_cert(void *_vpninfo, const char *reason)
{
struct openconnect_info *vpninfo = _vpninfo;
char fingerprint[SHA1_SIZE * 2 + 1];
const char *fingerprint;
struct accepted_cert *this;
int ret;

if (nocertcheck)
return 0;

ret = openconnect_get_cert_sha1(vpninfo, peer_cert, fingerprint);
if (ret)
return ret;
fingerprint = openconnect_get_peer_cert_hash(vpninfo);

for (this = accepted_certs; this; this = this->next) {
if (!strcasecmp(this->host, vpninfo->hostname) &&
Expand Down Expand Up @@ -1587,9 +1578,9 @@ static int validate_peer_cert(void *_vpninfo, OPENCONNECT_X509 *peer_cert,
}
free(response);

details = openconnect_get_cert_details(vpninfo, peer_cert);
details = openconnect_get_peer_cert_details(vpninfo);
fputs(details, stderr);
free(details);
openconnect_free_cert_info(vpninfo, details);
fprintf(stderr, _("SHA1 fingerprint: %s\n"), fingerprint);
}
}
Expand Down
5 changes: 3 additions & 2 deletions openconnect-internal.h
Expand Up @@ -282,7 +282,8 @@ struct openconnect_info {
openconnect_unlock_token_vfn unlock_token;
void *tok_cbdata;

OPENCONNECT_X509 *peer_cert;
void *peer_cert;
char *peer_cert_hash;

char *cookie; /* Pointer to within cookies list */
struct oc_vpn_option *cookies;
Expand Down Expand Up @@ -621,7 +622,7 @@ void openconnect_clear_cookies(struct openconnect_info *vpninfo);
int openconnect_open_https(struct openconnect_info *vpninfo);
void openconnect_close_https(struct openconnect_info *vpninfo, int final);
int cstp_handshake(struct openconnect_info *vpninfo, unsigned init);
int get_cert_md5_fingerprint(struct openconnect_info *vpninfo, OPENCONNECT_X509 *cert,
int get_cert_md5_fingerprint(struct openconnect_info *vpninfo, void *cert,
char *buf);
int openconnect_sha1(unsigned char *result, void *data, int len);
int openconnect_md5(unsigned char *result, void *data, int len);
Expand Down

0 comments on commit 1cc5b5c

Please sign in to comment.