Ejemplo n.º 1
0
static int get_comp(str* res, int local, int issuer, int nid, sip_msg_t* msg)
{
	static char buf[1024];
	X509* cert;
	struct tcp_connection* c;
	X509_NAME* name;
	X509_NAME_ENTRY* e;
	ASN1_STRING* asn1;
	int index, text_len;
	char* elem;
	unsigned char* text_s;
	       
	text_s = 0;

	if (get_cert(&cert, &c, msg, local) < 0) return -1;

	name = issuer ? X509_get_issuer_name(cert) : X509_get_subject_name(cert);
	if (!name) {
		ERR("Cannot extract subject or issuer name from peer certificate\n");
		goto err;
	}

	index = X509_NAME_get_index_by_NID(name, nid, -1);
	if (index == -1) {
		switch(nid) {
		case NID_commonName:             elem = "CommonName";              break;
		case NID_organizationName:       elem = "OrganizationName";        break;
		case NID_organizationalUnitName: elem = "OrganizationalUnitUname"; break;
		case NID_countryName:            elem = "CountryName";             break;
		case NID_stateOrProvinceName:    elem = "StateOrProvinceName";     break;
		case NID_localityName:           elem = "LocalityName";            break;
		case NID_userId:                 elem = "UserID";                  break;
		default:                         elem = "Unknown";                 break;
		}
		DBG("Element %s not found in certificate subject/issuer\n", elem);
		goto err;
	}

	e = X509_NAME_get_entry(name, index);
	asn1 = X509_NAME_ENTRY_get_data(e);
	text_len = ASN1_STRING_to_UTF8(&text_s, asn1);
	if (text_len < 0 || text_len >= 1024) {
		ERR("Error converting ASN1 string\n");
		goto err;
	}
	memcpy(buf, text_s, text_len);
	res->s = buf;
	res->len = text_len;

	OPENSSL_free(text_s);
	if (!local) X509_free(cert);
	tcpconn_put(c);
	return 0;

 err:
	if (text_s) OPENSSL_free(text_s);
	if (!local) X509_free(cert);
	tcpconn_put(c);
	return -1;
}
Ejemplo n.º 2
0
int tlsops_sn(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	static char buf[INT2STR_MAX_LEN];
	X509* cert;
	struct tcp_connection* c;
	int my, serial;
	char* sn;

	if (param->pvn.u.isname.name.n & CERT_PEER) {
		my = 0;
	} else if (param->pvn.u.isname.name.n & CERT_LOCAL) {
		my = 1;
	} else {
		LM_CRIT("could not determine certificate\n");
		return pv_get_null(msg, param, res);
	}
	
	if (get_cert(&cert, &c, msg, my) < 0)
		return pv_get_null(msg, param, res);
	
	serial = ASN1_INTEGER_get(X509_get_serialNumber(cert));
	sn = int2str( serial, &res->rs.len);
	memcpy(buf, sn, res->rs.len);
	res->rs.s = buf;
	res->ri = serial;
	res->flags = PV_VAL_STR | PV_VAL_INT;	
	
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return 0;
}
Ejemplo n.º 3
0
int tlsops_cert_version(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	static char buf[INT2STR_MAX_LEN];
	X509* cert;
	struct tcp_connection* c;
	char* version;
	int my;

	if (param->pvn.u.isname.name.n & CERT_PEER) {
		my = 0;
	} else if (param->pvn.u.isname.name.n & CERT_LOCAL) {
		my = 1;
	} else {
		LM_CRIT("bug in call to tlsops_cert_version\n");
		return pv_get_null(msg, param, res);
	}

	if (get_cert(&cert, &c, msg, my) < 0) return -1;
	version = int2str(X509_get_version(cert), &res->rs.len);
	memcpy(buf, version, res->rs.len);
	res->rs.s = buf;
	res->flags = PV_VAL_STR;
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return 0;
}
Ejemplo n.º 4
0
static int test_ocsp_url_svcloc_new(void)
{
    static const char *  urls[] = {
        "www.openssl.org",
        "www.openssl.net",
        NULL
    };

    X509 *issuer = NULL;
    X509_EXTENSION * ext = NULL;
    int ret = 0;

    if (!TEST_true(get_cert(&issuer)))
        goto err;

    /*
     * Test calling this ocsp method to catch any memory leak
     */
    ext = OCSP_url_svcloc_new(X509_get_issuer_name(issuer), urls);
    if (!TEST_ptr(ext))
        goto err;

    X509_EXTENSION_free(ext);
    ret = 1;
err:
    X509_free(issuer);
    return ret;
}
Ejemplo n.º 5
0
STACK_OF(X509) *get_cert_store(int *ids){
    STACK_OF(X509) *store = sk_X509_new(NULL);
    while(ids && ((*ids) != -1)){
        sk_X509_push(store, get_cert(*ids));
        ids++;
    }
    return store;
}
Ejemplo n.º 6
0
static int get_validity(str* res, int local, int bound, sip_msg_t* msg)
{
#define NOT_BEFORE 0
#define NOT_AFTER 1
    static char buf[1024];
    X509* cert;
    struct tcp_connection* c;
    BUF_MEM* p;
    BIO* mem = 0;
    ASN1_TIME* date;

    if (get_cert(&cert, &c, msg, local) < 0) return -1;

    switch (bound) {
    case NOT_BEFORE:
        date = X509_get_notBefore(cert);
        break;
    case NOT_AFTER:
        date = X509_get_notAfter(cert);
        break;
    default:
        BUG("Unexpected parameter value \"%d\"\n", bound);
        goto err;
    }

    mem = BIO_new(BIO_s_mem());
    if (!mem) {
        ERR("Error while creating memory BIO\n");
        goto err;
    }

    if (!ASN1_TIME_print(mem, date)) {
        ERR("Error while printing certificate date/time\n");
        goto err;
    }

    BIO_get_mem_ptr(mem, &p);
    if (p->length >= 1024) {
        ERR("Date/time too long\n");
        goto err;
    }
    memcpy(buf, p->data, p->length);
    res->s = buf;
    res->len = p->length;

    BIO_free(mem);
    if (!local) X509_free(cert);
    tcpconn_put(c);
    return 0;
err:
    if (mem) BIO_free(mem);
    if (!local) X509_free(cert);
    tcpconn_put(c);
    return -1;
}
Ejemplo n.º 7
0
int tlsops_validity(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	static char buf[1024];
	X509* cert;
	struct tcp_connection* c;
	BUF_MEM* p;
	BIO* mem = 0;
	ASN1_TIME* date;
	int my = 0;

	if (get_cert(&cert, &c, msg, my) < 0) return -1;

	switch (param->pvn.u.isname.name.n) {
	case CERT_NOTBEFORE: date = X509_get_notBefore(cert); break;
	case CERT_NOTAFTER:  date = X509_get_notAfter(cert);  break;
	default:
		LM_CRIT("unexpected parameter value \"%d\"\n", param->pvn.u.isname.name.n);
		goto err;
	}

	mem = BIO_new(BIO_s_mem());
	if (!mem) {
		LM_ERR("failed to create memory BIO\n");
		goto err;
	}

	if (!ASN1_TIME_print(mem, date)) {
		LM_ERR("failed to print certificate date/time\n");
		goto err;
	}
	
	BIO_get_mem_ptr(mem, &p);
	if (p->length >= 1024) {
		LM_ERR("Date/time too long\n");
		goto err;
	}
	memcpy(buf, p->data, p->length);
	res->rs.s = buf;
	res->rs.len = p->length;
	res->flags = PV_VAL_STR ;

	BIO_free(mem);
	if (!my) X509_free(cert);
	tcpconn_put(c);

	return 0;
err:
	if (mem) BIO_free(mem);
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return pv_get_null(msg, param, res);
}
Ejemplo n.º 8
0
int
main(int argc,char *argv[])
{
  unsigned char *fpr;
  size_t fpr_len;
  char *url;
  int rc;
  IOBUF iobuf;

  if(argc!=2)
    {
      printf("cert-test [name]\n");
      return 1;
    }

  printf("CERT lookup on %s\n",argv[1]);

  rc=get_cert(argv[1],16384,&iobuf,&fpr,&fpr_len,&url);
  if(rc==-1)
    printf("error\n");
  else if(rc==0)
    printf("no answer\n");
  else if(rc==1)
    {
      printf("key found: %d bytes\n",(int)iobuf_get_temp_length(iobuf));
      iobuf_close(iobuf);
    }
  else if(rc==2)
    {
      if(fpr)
	{
	  size_t i;
	  printf("Fingerprint found (%d bytes): ",(int)fpr_len);
	  for(i=0;i<fpr_len;i++)
	    printf("%02X",fpr[i]);
	  printf("\n");
	}
      else
	printf("No fingerprint found\n");

      if(url)
	printf("URL found: %s\n",url);
      else
	printf("No URL found\n");

      xfree(fpr);
      xfree(url);
    }

  return 0;
}
Ejemplo n.º 9
0
static const char *obtain_cert(const char *hostname, const char *proto, unsigned port,
				const char *app_proto, unsigned quiet)
{
	socket_st hd;
	char txt_port[16];
	unsigned udp = 0;
	static char tmpfile[32];
	int fd, ret;
	const char *str = "Obtaining certificate from";
	const char *service;

	if (strcmp(proto, "udp") == 0)
		udp = 1;
	else if (strcmp(proto, "tcp") != 0) {
		/* we cannot handle this protocol */
		return NULL;
	}

	strcpy(tmpfile, "danetool-certXXXXXX");

	sockets_init();
	snprintf(txt_port, sizeof(txt_port), "%u", port);

	if (quiet)
		str = NULL;
	service = port_to_service(txt_port, proto);
	socket_open(&hd, hostname, service, udp, str);

	if (app_proto == NULL) app_proto = service;
	socket_starttls(&hd, app_proto);

	umask(066);
	fd = mkstemp(tmpfile);
	if (fd == -1) {
		int e = errno;
		fprintf(stderr, "error[%d]: %s\n", __LINE__,
			strerror(e));
		exit(1);
	}

	ret = get_cert(&hd, hostname, udp, fd);
	close(fd);

	socket_bye(&hd);

	if (ret == -1)
		return NULL;
	else
		return tmpfile;
}
Ejemplo n.º 10
0
static int get_cert_version(str* res, int local, sip_msg_t* msg)
{
	static char buf[INT2STR_MAX_LEN];
	X509* cert;
	struct tcp_connection* c;
	char* version;

	if (get_cert(&cert, &c, msg, local) < 0) return -1;
	version = int2str(X509_get_version(cert), &res->len);
	memcpy(buf, version, res->len);
	res->s = buf;
	if (!local) X509_free(cert);
	tcpconn_put(c);
	return 0;
}
Ejemplo n.º 11
0
static int get_sn(str* res, int* ires, int local, sip_msg_t* msg)
{
	static char buf[INT2STR_MAX_LEN];
	X509* cert;
	struct tcp_connection* c;
	char* sn;
	int num;

	if (get_cert(&cert, &c, msg, local) < 0) return -1;

	num = ASN1_INTEGER_get(X509_get_serialNumber(cert));
	sn = int2str(num, &res->len);
	memcpy(buf, sn, res->len);
	res->s = buf;
	if (ires) *ires = num;
	if (!local) X509_free(cert);
	tcpconn_put(c);
	return 0;
}
Ejemplo n.º 12
0
/*
 * Initialize SSL/TLS connection.
 */
int
open_secure_connection(session *ssn)
{
	int r, e;
	SSL_CTX *ctx;

	if (!ssn->sslproto) {
		ctx = ssl23ctx;
	} else if (!strcasecmp(ssn->sslproto, "ssl3")) {
		ctx = ssl3ctx;
	} else if (!strcasecmp(ssn->sslproto, "tls1")) {
		ctx = tls1ctx;
	} else if (!strcasecmp(ssn->sslproto, "tls1.1")) {
#if OPENSSL_VERSION_NUMBER >= 0x01000100fL
		ctx = tls11ctx;
#else
		ctx = tls1ctx;
#endif
	} else if (!strcasecmp(ssn->sslproto, "tls1.2")) {
#if OPENSSL_VERSION_NUMBER >= 0x01000100fL
		ctx = tls12ctx;
#else
		ctx = tls1ctx;
#endif
	} else {
		ctx = ssl23ctx;
	}

	if (!(ssn->sslconn = SSL_new(ctx)))
		goto fail;

	SSL_set_fd(ssn->sslconn, ssn->socket);

	for (;;) {
		if ((r = SSL_connect(ssn->sslconn)) > 0)
			break;

		switch (SSL_get_error(ssn->sslconn, r)) {
		case SSL_ERROR_ZERO_RETURN:
			error("initiating SSL connection to %s; the "
			    "connection has been closed cleanly\n",
			    ssn->server);
			goto fail;
		case SSL_ERROR_NONE:
		case SSL_ERROR_WANT_CONNECT:
		case SSL_ERROR_WANT_ACCEPT:
		case SSL_ERROR_WANT_X509_LOOKUP:
		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_WRITE:
			break;
		case SSL_ERROR_SYSCALL:
			e = ERR_get_error();
			if (e == 0 && r == 0)
				error("initiating SSL connection to %s; EOF in "
				    "violation of the protocol\n", ssn->server);
			else if (e == 0 && r == -1)
				error("initiating SSL connection to %s; %s\n",
				    ssn->server, strerror(errno));
			else
				error("initiating SSL connection to %s; %s\n",
				    ssn->server, ERR_error_string(e, NULL));
			goto fail;
		case SSL_ERROR_SSL:
			error("initiating SSL connection to %s; %s\n",
			    ssn->server, ERR_error_string(ERR_get_error(),
			    NULL));
			goto fail;
		default:
			break;
		}
	}
	if (get_option_boolean("certificates") && get_cert(ssn) == -1)
		goto fail;

	return 0;

fail:
	ssn->sslconn = NULL;

	return -1;
}
Ejemplo n.º 13
0
int tlsops_alt(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	static char buf[1024];
	int type = GEN_URI, my = 0, n, found = 0, ind_local;
	STACK_OF(GENERAL_NAME)* names = 0;
	GENERAL_NAME* nm;
	X509* cert;
	struct tcp_connection* c;
	str text;
	struct ip_addr ip;

	ind_local = param->pvn.u.isname.name.n;

	if (ind_local & CERT_PEER) {
		my = 0;
		ind_local = ind_local ^ CERT_PEER;
	} else if (ind_local & CERT_LOCAL) {
		my = 1;
		ind_local = ind_local ^ CERT_LOCAL;
	} else {
		LM_CRIT("could not determine certificate\n");
		return pv_get_null(msg, param, res);
	}

	switch(ind_local) {
		case COMP_E:    type = GEN_EMAIL; break;
		case COMP_HOST: type = GEN_DNS;   break;
		case COMP_URI:  type = GEN_URI;   break;
		case COMP_IP:   type = GEN_IPADD; break;
		default:
			LM_CRIT("ind_local=%d\n", ind_local);
			return pv_get_null(msg, param, res);
	}

	if (get_cert(&cert, &c, msg, my) < 0) return -1;

	names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
	if (!names) {
		LM_ERR("cannot get certificate alternative subject\n");
		goto err;

	}

	for (n = 0; n < sk_GENERAL_NAME_num(names); n++) {
		nm = sk_GENERAL_NAME_value(names, n);
		if (nm->type != type) continue;
		switch(type) {
		case GEN_EMAIL:
		case GEN_DNS:
		case GEN_URI:
			text.s = (char*)nm->d.ia5->data;
			text.len = nm->d.ia5->length;
			if (text.len >= 1024) {
				LM_ERR("alternative subject text too long\n");
				goto err;
			}
			memcpy(buf, text.s, text.len);
			res->rs.s = buf;
			res->rs.len = text.len;
			res->flags = PV_VAL_STR;
			found = 1;
			break;

		case GEN_IPADD:
			ip.len = nm->d.iPAddress->length;
			ip.af = (ip.len == 16) ? AF_INET6 : AF_INET;
			memcpy(ip.u.addr, nm->d.iPAddress->data, ip.len);
			text.s = ip_addr2a(&ip);
			text.len = strlen(text.s);
			memcpy(buf, text.s, text.len);
			res->rs.s = buf;
			res->rs.len = text.len;
			res->flags = PV_VAL_STR;
			found = 1;
			break;
		}
		break;
	}
	if (!found) goto err;

	if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return 0;
 err:
	if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return pv_get_null(msg, param, res);
}
Ejemplo n.º 14
0
int tlsops_comp(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	static char buf[1024];
	X509* cert;
	struct tcp_connection* c;
	X509_NAME* name;
	X509_NAME_ENTRY* e;
	ASN1_STRING* asn1;
	int nid = NID_commonName, index, my = 0, issuer = 0, ind_local;
	char* elem;
	str text;

	text.s = 0;
	/* copy callback value as we modify it */
	ind_local = param->pvn.u.isname.name.n;

	DBG("DEBUG:tlsops:tlsops_comp: ind_local = %x", ind_local);
	if (ind_local & CERT_PEER) {
		my = 0;
		ind_local = ind_local ^ CERT_PEER;
	} else if (ind_local & CERT_LOCAL) {
		my = 1;
		ind_local = ind_local ^ CERT_LOCAL;
	} else {
		LM_CRIT("could not determine certificate\n");
		return pv_get_null(msg, param, res);
	}

	if (ind_local & CERT_SUBJECT) {
		issuer = 0;
		ind_local = ind_local ^ CERT_SUBJECT;
	} else if (ind_local & CERT_ISSUER) {
		issuer = 1;
		ind_local = ind_local ^ CERT_ISSUER;
	} else {
		LM_CRIT("could not determine subject or issuer\n");
		return pv_get_null(msg, param, res);
	}

	switch(ind_local) {
		case COMP_CN: nid = NID_commonName;             break;
		case COMP_O:  nid = NID_organizationName;       break;
		case COMP_OU: nid = NID_organizationalUnitName; break;
		case COMP_C:  nid = NID_countryName;            break;
		case COMP_ST: nid = NID_stateOrProvinceName;    break;
		case COMP_L:  nid = NID_localityName;           break;
		default:      nid = NID_undef;
	}

	if (get_cert(&cert, &c, msg, my) < 0) return -1;

	name = issuer ? X509_get_issuer_name(cert) : X509_get_subject_name(cert);
	if (!name) {
		LM_ERR("cannot extract subject or issuer name from peer"
				" certificate\n");
		goto err;
	}

	if (nid == NID_undef) { /* dump the whole cert info into buf */
		X509_NAME_oneline(name, buf, sizeof(buf));
		res->rs.s = buf;
		res->rs.len = strlen(buf);
		res->flags = PV_VAL_STR;
	} else {
		index = X509_NAME_get_index_by_NID(name, nid, -1);
		if (index == -1) {
			switch(ind_local) {
			case COMP_CN: elem = "CommonName";              break;
			case COMP_O:  elem = "OrganizationName";        break;
			case COMP_OU: elem = "OrganizationalUnitUname"; break;
			case COMP_C:  elem = "CountryName";             break;
			case COMP_ST: elem = "StateOrProvinceName";     break;
			case COMP_L:  elem = "LocalityName";            break;
			default:      elem = "Unknown";                 break;
			}
			DBG("DEBUG:tlsops:tlsops_comp: element %s not found in "
				"certificate subject/issuer\n", elem);
			goto err;
		}
	
		e = X509_NAME_get_entry(name, index);
		asn1 = X509_NAME_ENTRY_get_data(e);
		text.len = ASN1_STRING_to_UTF8((unsigned char**)(void*)&text.s, asn1);
		if (text.len < 0 || text.len >= 1024) {
			LM_ERR("failed to convert ASN1 string\n");
			goto err;
		}
		memcpy(buf, text.s, text.len);
		res->rs.s = buf;
		res->rs.len = text.len;
		res->flags = PV_VAL_STR;
	
		OPENSSL_free(text.s);
	}
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return 0;

 err:
	if (text.s) OPENSSL_free(text.s);
	if (!my) X509_free(cert);
	tcpconn_put(c);
	return pv_get_null(msg, param, res);
}
Ejemplo n.º 15
0
static int get_alt(str* res, int local, int type, sip_msg_t* msg)
{
	static char buf[1024];
	int n, found = 0;
	STACK_OF(GENERAL_NAME)* names = 0;
	GENERAL_NAME* nm;
	X509* cert;
	struct tcp_connection* c;
	str text;
	struct ip_addr ip;

	if (get_cert(&cert, &c, msg, local) < 0) return -1;

	names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
	if (!names) {
		DBG("Cannot get certificate alternative subject\n");
		goto err;

	}

	for (n = 0; n < sk_GENERAL_NAME_num(names); n++) {
		nm = sk_GENERAL_NAME_value(names, n);
		if (nm->type != type) continue;
		switch(type) {
		case GEN_EMAIL:
		case GEN_DNS:
		case GEN_URI:
			text.s = (char*)nm->d.ia5->data;
			text.len = nm->d.ia5->length;
			if (text.len >= 1024) {
				ERR("Alternative subject text too long\n");
				goto err;
			}
			memcpy(buf, text.s, text.len);
			res->s = buf;
			res->len = text.len;
			found = 1;
			break;

		case GEN_IPADD:
			ip.len = nm->d.iPAddress->length;
			ip.af = (ip.len == 16) ? AF_INET6 : AF_INET;
			memcpy(ip.u.addr, nm->d.iPAddress->data, ip.len);
			text.s = ip_addr2a(&ip);
			text.len = strlen(text.s);
			memcpy(buf, text.s, text.len);
			res->s = buf;
			res->len = text.len;
			found = 1;
			break;
		}
		break;
	}
	if (!found) goto err;

	if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
	if (!local) X509_free(cert);
	tcpconn_put(c);
	return 0;
 err:
	if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
	if (!local) X509_free(cert);
	tcpconn_put(c);
	return -1;
}
Ejemplo n.º 16
0
/*
 * Initialize SSL/TLS connection.
 */
int
open_secure_connection(session *ssn)
{
	int r, e;
	SSL_CTX *ctx;
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
	const SSL_METHOD *method;
#else		
	SSL_METHOD *method;
#endif

	method = NULL;

	if (ssn->sslproto && (!strncasecmp(ssn->sslproto, "ssl3", 4) ||
	    !strncasecmp(ssn->sslproto, "ssl2", 4)))
		method = SSLv23_client_method();
	else
		method = TLSv1_client_method();

	if (!(ctx = SSL_CTX_new(method)))
		goto fail;

	if (!(ssn->sslconn = SSL_new(ctx)))
		goto fail;

	SSL_set_fd(ssn->sslconn, ssn->socket);

	for (;;) {
		if ((r = SSL_connect(ssn->sslconn)) > 0)
			break;

		switch (SSL_get_error(ssn->sslconn, r)) {
		case SSL_ERROR_ZERO_RETURN:
			error("initiating SSL connection to %s; the "
			    "connection has been closed cleanly\n",
			    ssn->server);
			goto fail;
		case SSL_ERROR_NONE:
		case SSL_ERROR_WANT_CONNECT:
		case SSL_ERROR_WANT_ACCEPT:
		case SSL_ERROR_WANT_X509_LOOKUP:
		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_WRITE:
			break;
		case SSL_ERROR_SYSCALL:
			e = ERR_get_error();
			if (e == 0 && r == 0)
				error("initiating SSL connection to %s; EOF in "
				    "violation of the protocol\n", ssn->server);
			else if (e == 0 && r == -1)
				error("initiating SSL connection to %s; %s\n",
				    ssn->server, strerror(errno));
			else
				error("initiating SSL connection to %s; %s\n",
				    ssn->server, ERR_error_string(e, NULL));
			goto fail;
		case SSL_ERROR_SSL:
			error("initiating SSL connection to %s; %s\n",
			    ssn->server, ERR_error_string(ERR_get_error(),
			    NULL));
			goto fail;
		default:
			break;
		}
	}
	if (get_option_boolean("certificates") && get_cert(ssn) == -1)
		goto fail;

	SSL_CTX_free(ctx);

	return 0;

fail:
	ssn->sslconn = NULL;
	SSL_CTX_free(ctx);

	return -1;
}