cb.c 4.37 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
#include "tunala.h"

#ifndef NO_OPENSSL

/* For callbacks generating output, here are their file-descriptors. */
static FILE *fp_cb_ssl_info = NULL;
static FILE *fp_cb_ssl_verify = NULL;
/* Output level:
 *     0 = nothing,
 *     1 = minimal, just errors,
 *     2 = minimal, all steps,
 *     3 = detail, all steps */
static unsigned int cb_ssl_verify_level = 1;

/* Other static rubbish (to mirror s_cb.c where required) */
static int int_verify_depth = 10;

/* This function is largely borrowed from the one used in OpenSSL's "s_client"
 * and "s_server" utilities. */
void cb_ssl_info(const SSL *s, int where, int ret)
{
	const char *str1, *str2;
	int w;

	if(!fp_cb_ssl_info)
		return;

	w = where & ~SSL_ST_MASK;
	str1 = (w & SSL_ST_CONNECT ? "SSL_connect" : (w & SSL_ST_ACCEPT ?
				"SSL_accept" : "undefined")),
	str2 = SSL_state_string_long(s);

	if (where & SSL_CB_LOOP)
		fprintf(fp_cb_ssl_info, "(%s) %s\n", str1, str2);
	else if (where & SSL_CB_EXIT) {
		if (ret == 0)
			fprintf(fp_cb_ssl_info, "(%s) failed in %s\n", str1, str2);
/* In a non-blocking model, we get a few of these "error"s simply because we're
 * calling "reads" and "writes" on the state-machine that are virtual NOPs
 * simply to avoid wasting the time seeing if we *should* call them. Removing
 * this case makes the "-out_state" output a lot easier on the eye. */
#if 0
		else if (ret < 0)
			fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2);
#endif
	}
}

void cb_ssl_info_set_output(FILE *fp)
{
	fp_cb_ssl_info = fp;
}

static const char *int_reason_no_issuer = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
static const char *int_reason_not_yet = "X509_V_ERR_CERT_NOT_YET_VALID";
static const char *int_reason_before = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
static const char *int_reason_expired = "X509_V_ERR_CERT_HAS_EXPIRED";
static const char *int_reason_after = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";

/* Stolen wholesale from apps/s_cb.c :-) And since then, mutilated ... */
int cb_ssl_verify(int ok, X509_STORE_CTX *ctx)
{
	char buf1[256]; /* Used for the subject name */
	char buf2[256]; /* Used for the issuer name */
	const char *reason = NULL; /* Error reason (if any) */
	X509 *err_cert;
	int err, depth;

	if(!fp_cb_ssl_verify || (cb_ssl_verify_level == 0))
		return ok;
	err_cert = X509_STORE_CTX_get_current_cert(ctx);
	err = X509_STORE_CTX_get_error(ctx);
	depth = X509_STORE_CTX_get_error_depth(ctx);

	buf1[0] = buf2[0] = '\0';
	/* Fill buf1 */
	X509_NAME_oneline(X509_get_subject_name(err_cert), buf1, 256);
	/* Fill buf2 */
	X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf2, 256);
	switch (ctx->error) {
	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
		reason = int_reason_no_issuer;
		break;
	case X509_V_ERR_CERT_NOT_YET_VALID:
		reason = int_reason_not_yet;
		break;
	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
		reason = int_reason_before;
		break;
	case X509_V_ERR_CERT_HAS_EXPIRED:
		reason = int_reason_expired;
		break;
	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
		reason = int_reason_after;
		break;
	}

	if((cb_ssl_verify_level == 1) && ok)
		return ok;
	fprintf(fp_cb_ssl_verify, "chain-depth=%d, ", depth);
	if(reason)
		fprintf(fp_cb_ssl_verify, "error=%s\n", reason);
	else
		fprintf(fp_cb_ssl_verify, "error=%d\n", err);
	if(cb_ssl_verify_level < 3)
		return ok;
	fprintf(fp_cb_ssl_verify, "--> subject = %s\n", buf1);
	fprintf(fp_cb_ssl_verify, "--> issuer  = %s\n", buf2);
	if(!ok)
		fprintf(fp_cb_ssl_verify,"--> verify error:num=%d:%s\n",err,
			X509_verify_cert_error_string(err));
	fprintf(fp_cb_ssl_verify, "--> verify return:%d\n",ok);
	return ok;
}

void cb_ssl_verify_set_output(FILE *fp)
{
	fp_cb_ssl_verify = fp;
}

void cb_ssl_verify_set_depth(unsigned int verify_depth)
{
	int_verify_depth = verify_depth;
}

void cb_ssl_verify_set_level(unsigned int level)
{
	if(level < 4)
		cb_ssl_verify_level = level;
}

RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength)
{
	/* TODO: Perhaps make it so our global key can be generated on-the-fly
	 * after certain intervals? */
	static RSA *rsa_tmp = NULL;
	BIGNUM *bn = NULL;
	int ok = 1;
	if(!rsa_tmp) {
		ok = 0;
		if(!(bn = BN_new()))
			goto end;
		if(!BN_set_word(bn, RSA_F4))
			goto end;
		if(!(rsa_tmp = RSA_new()))
			goto end;
		if(!RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL))
			goto end;
		ok = 1;
	}
end:
	if(bn)
		BN_free(bn);
	if(!ok) {
		RSA_free(rsa_tmp);
		rsa_tmp = NULL;
	}
	return rsa_tmp;
}

#endif /* !defined(NO_OPENSSL) */