Exemplo n.º 1
0
static int
tls_get_peer_cert_hash(struct tls *ctx, char **hash)
{
	unsigned char d[EVP_MAX_MD_SIZE];
	char *dhex = NULL;
	unsigned int dlen;
	int rv = -1;

	*hash = NULL;
	if (ctx->ssl_peer_cert == NULL)
		return (0);

	if (X509_digest(ctx->ssl_peer_cert, EVP_sha256(), d, &dlen) != 1) {
		tls_set_errorx(ctx, "digest failed");
		goto err;
	}

	if (tls_hex_string(d, dlen, &dhex, NULL) != 0) {
		tls_set_errorx(ctx, "digest hex string failed");
		goto err;
	}

	if (asprintf(hash, "SHA256:%s", dhex) == -1) {
		tls_set_errorx(ctx, "out of memory");
		*hash = NULL;
		goto err;
	}

	rv = 0;

err:
	free(dhex);

	return (rv);
}
Exemplo n.º 2
0
int
tls_parse_cert(struct tls *ctx, struct tls_cert **cert_p, const char *fingerprint_algo, X509 *x509)
{
	struct tls_cert *cert = NULL;
	X509_NAME *subject, *issuer;
	int ret = -1;
	long version;

	*cert_p = NULL;

	version = X509_get_version(x509);
	if (version < 0) {
		tls_set_errorx(ctx, "invalid version");
		return -1;
	}

	subject = X509_get_subject_name(x509);
	if (!subject) {
		tls_set_errorx(ctx, "cert does not have subject");
		return -1;
	}

	issuer = X509_get_issuer_name(x509);
	if (!issuer) {
		tls_set_errorx(ctx, "cert does not have issuer");
		return -1;
	}

	cert = calloc(sizeof *cert, 1);
	if (!cert) {
		tls_set_error(ctx, "calloc");
		goto failed;
	}
	cert->version = version;

	if (fingerprint_algo) {
		cert->fingerprint = tls_calc_fingerprint(ctx, x509, fingerprint_algo, &cert->fingerprint_size);
		if (!cert->fingerprint)
			goto failed;
	}

	ret = tls_get_dname(ctx, subject, &cert->subject);
	if (ret == 0)
		ret = tls_get_dname(ctx, issuer, &cert->issuer);
	if (ret == 0)
		ret = tls_cert_get_altnames(ctx, cert, x509);
	if (ret == 0)
		ret = tls_parse_time(ctx, X509_get_notBefore(x509), &cert->not_before);
	if (ret == 0)
		ret = tls_parse_time(ctx, X509_get_notAfter(x509), &cert->not_after);
	if (ret == 0)
		ret = tls_parse_bigint(ctx, X509_get_serialNumber(x509), &cert->serial);
	if (ret == 0) {
		*cert_p = cert;
		return 0;
	}
failed:
	tls_cert_free(cert);
	return ret;
}
Exemplo n.º 3
0
int
tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
    void *cb_arg)
{
	int rv = -1;
	BIO *bio;

	if (read_cb == NULL || write_cb == NULL) {
		tls_set_errorx(ctx, "no callbacks provided");
		goto err;
	}

	ctx->read_cb = read_cb;
	ctx->write_cb = write_cb;
	ctx->cb_arg = cb_arg;

	if ((bio = BIO_new(bio_s_cb())) == NULL) {
		tls_set_errorx(ctx, "failed to create callback i/o");
		goto err;
	}
	bio->ptr = ctx;
	bio->init = 1;

	SSL_set_bio(ctx->ssl_conn, bio, bio);

	rv = 0;

 err:
	return (rv);
}
Exemplo n.º 4
0
int
tls_handshake(struct tls *ctx)
{
	int rv = -1;

	tls_error_clear(&ctx->error);

	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
		tls_set_errorx(ctx, "invalid operation for context");
		goto out;
	}

	if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) {
		tls_set_errorx(ctx, "handshake already completed");
		goto out;
	}

	if ((ctx->flags & TLS_CLIENT) != 0)
		rv = tls_handshake_client(ctx);
	else if ((ctx->flags & TLS_SERVER_CONN) != 0)
		rv = tls_handshake_server(ctx);

	if (rv == 0) {
		ctx->ssl_peer_cert = SSL_get_peer_certificate(ctx->ssl_conn);
		ctx->ssl_peer_chain = SSL_get_peer_cert_chain(ctx->ssl_conn);
		if (tls_conninfo_populate(ctx) == -1)
			rv = -1;
		if (ctx->ocsp == NULL)
			ctx->ocsp = tls_ocsp_setup_from_peer(ctx);
	}
 out:
	/* Prevent callers from performing incorrect error handling */
	errno = 0;
	return (rv);
}
Exemplo n.º 5
0
static int
check_invalid_bytes(struct tls *ctx, unsigned char *data, unsigned int len,
		    int ascii_only, const char *desc)
{
	unsigned int i, c;

	/* data is utf8 string, check for crap */
	for (i = 0; i < len; i++) {
		c = data[i];

		if (ascii_only && (c & 0x80) != 0) {
			tls_set_errorx(ctx, "invalid %s: contains non-ascii in ascii string", desc);
			goto failed;
		} else if (c < 0x20) {
			/* ascii control chars, including NUL */
			if (c != '\t' && c != '\n' && c != '\r') {
				tls_set_errorx(ctx, "invalid %s: contains C0 control char", desc);
				goto failed;
			}
		} else if (c == 0xC2 && (i + 1) < len) {
			/* C1 control chars in UTF-8: \xc2\x80 - \xc2\x9f */
			c = data[i + 1];
			if (c >= 0x80 && c <= 0x9F) {
				tls_set_errorx(ctx, "invalid %s: contains C1 control char", desc);
				goto failed;
			}
		} else if (c == 0x7F) {
			tls_set_errorx(ctx, "invalid %s: contains DEL char", desc);
			goto failed;
		}
	}
	return 0;
failed:
	return -1;
}
Exemplo n.º 6
0
int
tls_get_peer_cert(struct tls *ctx, struct tls_cert **cert_p, const char *fingerprint_algo)
{
	SSL *conn = ctx->ssl_conn;
	X509 *peer;
	int res;

	*cert_p = NULL;

	if (!conn) {
		tls_set_errorx(ctx, "not connected");
		return -1;
	}

	peer = SSL_get_peer_certificate(conn);
	if (!peer) {
		tls_set_errorx(ctx, "peer does not have cert");
		return TLS_NO_CERT;
	}

	res = tls_parse_cert(ctx, cert_p, fingerprint_algo, peer);
	if (res == 0)
		check_verify_error(ctx, *cert_p);
	return res;
}
Exemplo n.º 7
0
int
tls_configure_ssl_verify(struct tls *ctx, int verify)
{
	SSL_CTX_set_verify(ctx->ssl_ctx, verify, NULL);

	if (ctx->config->ca_mem != NULL) {
		/* XXX do this in set. */
		if (ctx->config->ca_len > INT_MAX) {
			tls_set_errorx(ctx, "ca too long");
			goto err;
		}
		if (SSL_CTX_load_verify_mem(ctx->ssl_ctx,
		    ctx->config->ca_mem, ctx->config->ca_len) != 1) {
			tls_set_errorx(ctx, "ssl verify memory setup failure");
			goto err;
		}
	} else if (SSL_CTX_load_verify_locations(ctx->ssl_ctx,
	    ctx->config->ca_file, ctx->config->ca_path) != 1) {
		tls_set_errorx(ctx, "ssl verify setup failure");
		goto err;
	}
	if (ctx->config->verify_depth >= 0)
		SSL_CTX_set_verify_depth(ctx->ssl_ctx,
		    ctx->config->verify_depth);

	return (0);

 err:
	return (-1);
}
Exemplo n.º 8
0
int
tls_close(struct tls *ctx)
{
	int ssl_ret;
	int rv = 0;

	tls_error_clear(&ctx->error);

	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
		tls_set_errorx(ctx, "invalid operation for context");
		rv = -1;
		goto out;
	}

	if (ctx->state & TLS_SSL_NEEDS_SHUTDOWN) {
		ERR_clear_error();
		ssl_ret = SSL_shutdown(ctx->ssl_conn);
		if (ssl_ret < 0) {
			rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret,
			    "shutdown");
			if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
				goto out;
		}
		ctx->state &= ~TLS_SSL_NEEDS_SHUTDOWN;
	}

	if (ctx->socket != -1) {
		if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
			if (rv == 0 &&
			    errno != ENOTCONN && errno != ECONNRESET) {
				tls_set_error(ctx, "shutdown");
				rv = -1;
			}
		}
		if (close(ctx->socket) != 0) {
			if (rv == 0) {
				tls_set_error(ctx, "close");
				rv = -1;
			}
		}
		ctx->socket = -1;
	}

	if ((ctx->state & TLS_EOF_NO_CLOSE_NOTIFY) != 0) {
		tls_set_errorx(ctx, "EOF without close notify");
		rv = -1;
	}

 out:
	/* Prevent callers from performing incorrect error handling */
	errno = 0;
	return (rv);
}
Exemplo n.º 9
0
int
tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx)
{
	SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
	SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

	SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2);
	SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv3);

	SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1);
	SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
	SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_2);

	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0)
		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1);
	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0)
		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0)
		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2);

	if (ctx->config->alpn != NULL) {
		if (SSL_CTX_set_alpn_protos(ssl_ctx, ctx->config->alpn,
		    ctx->config->alpn_len) != 0) {
			tls_set_errorx(ctx, "failed to set alpn");
			goto err;
		}
	}

	if (ctx->config->ciphers != NULL) {
		if (SSL_CTX_set_cipher_list(ssl_ctx,
		    ctx->config->ciphers) != 1) {
			tls_set_errorx(ctx, "failed to set ciphers");
			goto err;
		}
	}

	if (ctx->config->verify_time == 0) {
		X509_VERIFY_PARAM_set_flags(ssl_ctx->param,
		    X509_V_FLAG_NO_CHECK_TIME);
	}

	/* Disable any form of session caching by default */
	SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_OFF);
	SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);

	return (0);

 err:
	return (-1);
}
Exemplo n.º 10
0
int
tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret, const char *prefix)
{
	const char *errstr = "unknown error";
	unsigned long err;
	int ssl_err;

	ssl_err = SSL_get_error(ssl_conn, ssl_ret);
	switch (ssl_err) {
	case SSL_ERROR_NONE:
	case SSL_ERROR_ZERO_RETURN:
		return (0);

	case SSL_ERROR_WANT_READ:
		return (TLS_WANT_POLLIN);

	case SSL_ERROR_WANT_WRITE:
		return (TLS_WANT_POLLOUT);

	case SSL_ERROR_SYSCALL:
		if ((err = ERR_peek_error()) != 0) {
			errstr = ERR_error_string(err, NULL);
		} else if (ssl_ret == 0) {
			if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) {
				ctx->state |= TLS_EOF_NO_CLOSE_NOTIFY;
				return (0);
			}
			errstr = "unexpected EOF";
		} else if (ssl_ret == -1) {
			errstr = strerror(errno);
		}
		tls_set_errorx(ctx, "%s failed: %s", prefix, errstr);
		return (-1);

	case SSL_ERROR_SSL:
		if ((err = ERR_peek_error()) != 0) {
			errstr = ERR_error_string(err, NULL);
		}
		tls_set_errorx(ctx, "%s failed: %s", prefix, errstr);
		return (-1);

	case SSL_ERROR_WANT_CONNECT:
	case SSL_ERROR_WANT_ACCEPT:
	case SSL_ERROR_WANT_X509_LOOKUP:
	default:
		tls_set_errorx(ctx, "%s failed (%i)", prefix, ssl_err);
		return (-1);
	}
}
Exemplo n.º 11
0
int
tls_handshake_client(struct tls *ctx)
{
	X509 *cert = NULL;
	int match, ssl_ret;
	int rv = -1;

	if ((ctx->flags & TLS_CLIENT) == 0) {
		tls_set_errorx(ctx, "not a client context");
		goto err;
	}

	if ((ctx->state & TLS_CONNECTED) == 0) {
		tls_set_errorx(ctx, "context not connected");
		goto err;
	}

	ctx->state |= TLS_SSL_NEEDS_SHUTDOWN;

	ERR_clear_error();
	if ((ssl_ret = SSL_connect(ctx->ssl_conn)) != 1) {
		rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "handshake");
		goto err;
	}

	if (ctx->config->verify_name) {
		cert = SSL_get_peer_certificate(ctx->ssl_conn);
		if (cert == NULL) {
			tls_set_errorx(ctx, "no server certificate");
			goto err;
		}
		if (tls_check_name(ctx, cert, ctx->servername, &match) == -1)
			goto err;
		if (!match) {
			tls_set_errorx(ctx, "name `%s' not present in"
			    " server certificate", ctx->servername);
			goto err;
		}
	}

	ctx->state |= TLS_HANDSHAKE_COMPLETE;
	rv = 0;

 err:
	X509_free(cert);

	return (rv);
}
Exemplo n.º 12
0
int
tls_configure_ssl(struct tls *ctx)
{
	SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
	SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

	SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
	SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);

	SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
	SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1);
	SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);

	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0)
		SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0)
		SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1);
	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0)
		SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);

	if (ctx->config->ciphers != NULL) {
		if (SSL_CTX_set_cipher_list(ctx->ssl_ctx,
		    ctx->config->ciphers) != 1) {
			tls_set_errorx(ctx, "failed to set ciphers");
			goto err;
		}
	}

	SSL_CTX_set_info_callback(ctx->ssl_ctx, tls_info_callback);

	return (0);

err:
	return (-1);
}
Exemplo n.º 13
0
/* Convert ASN1_INTEGER to decimal string string */
static int
tls_parse_bigint(struct tls *ctx, const ASN1_INTEGER *asn1int, const char **dst_p)
{
	long small;
	BIGNUM *big;
	char *tmp, buf[64];

	*dst_p = NULL;
	small = ASN1_INTEGER_get(asn1int);
	if (small < 0) {
		big = ASN1_INTEGER_to_BN(asn1int, NULL);
		if (big) {
			tmp = BN_bn2dec(big);
			if (tmp)
				*dst_p = strdup(tmp);
			OPENSSL_free(tmp);
		}
		BN_free(big);
	} else {
		snprintf(buf, sizeof buf, "%lu", small);
		*dst_p = strdup(buf);
	}
	if (*dst_p)
		return 0;

	tls_set_errorx(ctx, "cannot parse serial");
	return -1;
}
Exemplo n.º 14
0
static int
tls_load_alt_ia5string(struct tls *ctx, ASN1_IA5STRING *ia5str, struct tls_cert *cert, int slot_type, int minchars, int maxchars, const char *desc)
{
	struct tls_cert_general_name *slot;
	const char *data;
	int len;

	slot = &cert->subject_alt_names[cert->subject_alt_name_count];

	len = tls_parse_asn1string(ctx, ia5str, &data, minchars, maxchars, desc);
	if (len < 0)
		return 0;

	/*
	 * Per RFC 5280 section 4.2.1.6:
	 * " " is a legal domain name, but that
	 * dNSName must be rejected.
	 */
	if (len == 1 && data[0] == ' ') {
		tls_set_errorx(ctx, "invalid %s: single space", desc);
		return -1;
	}

	slot->name_value = data;
	slot->name_type = slot_type;

	cert->subject_alt_name_count++;
	return 0;
}
Exemplo n.º 15
0
int
tls_handshake(struct tls *ctx)
{
	int rv = -1;

	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
		tls_set_errorx(ctx, "invalid operation for context");
		goto out;
	}

	if (ctx->conninfo == NULL &&
	    (ctx->conninfo = calloc(1, sizeof(*ctx->conninfo))) == NULL)
		goto out;

	if ((ctx->flags & TLS_CLIENT) != 0)
		rv = tls_handshake_client(ctx);
	else if ((ctx->flags & TLS_SERVER_CONN) != 0)
		rv = tls_handshake_server(ctx);

	if (rv == 0) {
		ctx->ssl_peer_cert =  SSL_get_peer_certificate(ctx->ssl_conn);
		if (tls_get_conninfo(ctx) == -1)
		    rv = -1;
	}
 out:
	/* Prevent callers from performing incorrect error handling */
	errno = 0;
	return (rv);
}
Exemplo n.º 16
0
ssize_t
tls_write(struct tls *ctx, const void *buf, size_t buflen)
{
	ssize_t rv = -1;
	int ssl_ret;

	tls_error_clear(&ctx->error);

	if ((ctx->state & TLS_HANDSHAKE_COMPLETE) == 0) {
		if ((rv = tls_handshake(ctx)) != 0)
			goto out;
	}

	if (buflen > INT_MAX) {
		tls_set_errorx(ctx, "buflen too long");
		goto out;
	}

	ERR_clear_error();
	if ((ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen)) > 0) {
		rv = (ssize_t)ssl_ret;
		goto out;
	}
	rv = (ssize_t)tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "write");

 out:
	/* Prevent callers from performing incorrect error handling */
	errno = 0;
	return (rv);
}
Exemplo n.º 17
0
int
tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret, const char *prefix)
{
	const char *errstr = "unknown error";
	unsigned long err;
	int ssl_err;

	ssl_err = SSL_get_error(ssl_conn, ssl_ret);
	switch (ssl_err) {
	case SSL_ERROR_NONE:
	case SSL_ERROR_ZERO_RETURN:
		return (0);

	case SSL_ERROR_WANT_READ:
		return (TLS_READ_AGAIN);

	case SSL_ERROR_WANT_WRITE:
		return (TLS_WRITE_AGAIN);

	case SSL_ERROR_SYSCALL:
		if ((err = ERR_peek_error()) != 0) {
			errstr = ERR_error_string(err, NULL);
		} else if (ssl_ret == 0) {
			errstr = "EOF";
		} else if (ssl_ret == -1) {
			errstr = strerror(errno);
		}
		tls_set_errorx(ctx, "%s failed: %s", prefix, errstr);
		return (-1);

	case SSL_ERROR_SSL:
		if ((err = ERR_peek_error()) != 0) {
			errstr = ERR_error_string(err, NULL);
		}
		tls_set_errorx(ctx, "%s failed: %s", prefix, errstr);
		return (-1);

	case SSL_ERROR_WANT_CONNECT:
	case SSL_ERROR_WANT_ACCEPT:
	case SSL_ERROR_WANT_X509_LOOKUP:
	default:
		tls_set_errorx(ctx, "%s failed (%i)", prefix, ssl_err);
		return (-1);
	}
}
Exemplo n.º 18
0
static int
tls_check_common_name(struct tls *ctx, X509 *cert, const char *name)
{
	X509_NAME *subject_name;
	char *common_name = NULL;
	union tls_addr addrbuf;
	int common_name_len;
	int rv = -1;

	subject_name = X509_get_subject_name(cert);
	if (subject_name == NULL)
		goto out;

	common_name_len = X509_NAME_get_text_by_NID(subject_name,
	    NID_commonName, NULL, 0);
	if (common_name_len < 0)
		goto out;

	common_name = calloc(common_name_len + 1, 1);
	if (common_name == NULL)
		goto out;

	X509_NAME_get_text_by_NID(subject_name, NID_commonName, common_name,
	    common_name_len + 1);

	/* NUL bytes in CN? */
	if (common_name_len < 0 ||
	    (size_t)common_name_len != strlen(common_name)) {
		tls_set_errorx(ctx, "error verifying name '%s': "
		    "NUL byte in Common Name field, "
		    "probably a malicious certificate", name);
		rv = -2;
		goto out;
	}

	if (inet_pton(AF_INET,  name, &addrbuf) == 1 ||
	    inet_pton(AF_INET6, name, &addrbuf) == 1) {
		/*
		 * We don't want to attempt wildcard matching against IP
		 * addresses, so perform a simple comparison here.
		 */
		if (strcmp(common_name, name) == 0)
			rv = 0;
		else
			rv = -1;
		goto out;
	}

	if (tls_match_name(common_name, name) == 0)
		rv = 0;
 out:
	free(common_name);
	return rv;
}
Exemplo n.º 19
0
int
tls_accept_fds(struct tls *ctx, struct tls **cctx, int fd_read, int fd_write)
{
	struct tls *conn_ctx = NULL;

	if ((ctx->flags & TLS_SERVER) == 0) {
		tls_set_errorx(ctx, "not a server context");
		goto err;
	}

	if ((conn_ctx = tls_server_conn(ctx)) == NULL) {
		tls_set_errorx(ctx, "connection context failure");
		goto err;
	}

	if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
		tls_set_errorx(ctx, "ssl failure");
		goto err;
	}
	if (SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx) != 1) {
		tls_set_errorx(ctx, "ssl application data failure");
		goto err;
	}
	if (SSL_set_rfd(conn_ctx->ssl_conn, fd_read) != 1 ||
	    SSL_set_wfd(conn_ctx->ssl_conn, fd_write) != 1) {
		tls_set_errorx(ctx, "ssl file descriptor failure");
		goto err;
	}

	*cctx = conn_ctx;

	return (0);

 err:
	tls_free(conn_ctx);

	*cctx = NULL;

	return (-1);
}
Exemplo n.º 20
0
static void *
tls_calc_fingerprint(struct tls *ctx, X509 *x509, const char *algo, size_t *outlen)
{
	const EVP_MD *md;
	void *res;
	int ret;
	unsigned int tmplen, mdlen;

	if (outlen)
		*outlen = 0;

	if (strcasecmp(algo, "sha1") == 0) {
		md = EVP_sha1();
	} else if (strcasecmp(algo, "sha256") == 0) {
		md = EVP_sha256();
	} else {
		tls_set_errorx(ctx, "invalid fingerprint algorithm");
		return NULL;
	}

	mdlen = EVP_MD_size(md);
	res = malloc(mdlen);
	if (!res) {
		tls_set_error(ctx, "malloc");
		return NULL;
	}

	ret = X509_digest(x509, md, res, &tmplen);
	if (ret != 1 || tmplen != mdlen) {
		free(res);
		tls_set_errorx(ctx, "X509_digest failed");
		return NULL;
	}

	if (outlen)
		*outlen = mdlen;

	return res;
}
Exemplo n.º 21
0
static int
tls_load_alt_ipaddr(struct tls *ctx, ASN1_OCTET_STRING *bin, struct tls_cert *cert)
{
	struct tls_cert_general_name *slot;
	void *data;
	int len;

	slot = &cert->subject_alt_names[cert->subject_alt_name_count];
	len = ASN1_STRING_length(bin);
	data = ASN1_STRING_data(bin);
	if (len < 0) {
		tls_set_errorx(ctx, "negative length for ipaddress");
		return -1;
	}

	/*
	 * Per RFC 5280 section 4.2.1.6:
	 * IPv4 must use 4 octets and IPv6 must use 16 octets.
	 */
	if (len == 4) {
		slot->name_type = TLS_CERT_GNAME_IPv4;
	} else if (len == 16) {
		slot->name_type = TLS_CERT_GNAME_IPv6;
	} else {
		tls_set_errorx(ctx, "invalid length for ipaddress");
		return -1;
	}

	slot->name_value = malloc(len);
	if (slot->name_value == NULL) {
		tls_set_error(ctx, "malloc");
		return -1;
	}

	memcpy((void *)slot->name_value, data, len);
	cert->subject_alt_name_count++;
	return 0;
}
Exemplo n.º 22
0
static int
tls_ssl_cert_verify_cb(X509_STORE_CTX *x509_ctx, void *arg)
{
	struct tls *ctx = arg;
	int x509_err;

	if (ctx->config->verify_cert == 0)
		return (1);

	if ((X509_verify_cert(x509_ctx)) < 0) {
		tls_set_errorx(ctx, "X509 verify cert failed");
		return (0);
	}

	x509_err = X509_STORE_CTX_get_error(x509_ctx);
	if (x509_err == X509_V_OK)
		return (1);

	tls_set_errorx(ctx, "certificate verification failed: %s",
	    X509_verify_cert_error_string(x509_err));

	return (0);
}
Exemplo n.º 23
0
int
tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
    const char *servername)
{
	int rv = -1;

	if (fd_read < 0 || fd_write < 0) {
		tls_set_errorx(ctx, "invalid file descriptors");
		goto err;
	}

	if (tls_connect_common(ctx, servername) != 0)
		goto err;

	if (SSL_set_rfd(ctx->ssl_conn, fd_read) != 1 ||
	    SSL_set_wfd(ctx->ssl_conn, fd_write) != 1) {
		tls_set_errorx(ctx, "ssl file descriptor failure");
		goto err;
	}

	rv = 0;
 err:
	return (rv);
}
Exemplo n.º 24
0
static int
tls_do_abort(struct tls *ctx)
{
	int ssl_ret, rv;

	ssl_ret = SSL_shutdown(ctx->ssl_conn);
	if (ssl_ret < 0) {
		rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "shutdown");
		if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
			return (rv);
	}

	tls_set_errorx(ctx, "unexpected handshake, closing connection");
	return -1;
}
Exemplo n.º 25
0
int
tls_configure_ssl(struct tls *ctx)
{
	SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
	SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
	SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);

	SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
	SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);

	SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
	SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1);
	SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);

	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0)
		SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0)
		SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1);
	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0)
		SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);

	if (ctx->config->ciphers != NULL) {
		if (SSL_CTX_set_cipher_list(ctx->ssl_ctx,
		    ctx->config->ciphers) != 1) {
			tls_set_errorx(ctx, "failed to set ciphers");
			goto err;
		}
	}

	SSL_CTX_set_info_callback(ctx->ssl_ctx, tls_info_callback);

#ifdef X509_V_FLAG_NO_CHECK_TIME
	if (ctx->config->verify_time == 0) {
		X509_VERIFY_PARAM *vfp = SSL_CTX_get0_param(ctx->ssl_ctx);
		X509_VERIFY_PARAM_set_flags(vfp, X509_V_FLAG_NO_CHECK_TIME);
	}
#endif

	return (0);

 err:
	return (-1);
}
Exemplo n.º 26
0
int
tls_connect_cbs(struct tls *ctx, tls_read_cb read_cb,
    tls_write_cb write_cb, void *cb_arg, const char *servername)
{
	int rv = -1;

	if (tls_connect_common(ctx, servername) != 0)
		goto err;

	if (tls_set_cbs(ctx, read_cb, write_cb, cb_arg) != 0) {
		tls_set_errorx(ctx, "callback registration failure");
		goto err;
	}

	rv = 0;

 err:
	return (rv);
}
Exemplo n.º 27
0
int
tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen)
{
	int ssl_ret;

	*outlen = 0;

	if (buflen > INT_MAX) {
		tls_set_errorx(ctx, "buflen too long");
		return (-1);
	}

	if (ctx->state & TLS_STATE_ABORT)
		return tls_do_abort(ctx);

	ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen);
	if (ssl_ret > 0) {
		*outlen = (size_t)ssl_ret;
		return (0);
	}

	return tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "write"); 
}
Exemplo n.º 28
0
int
tls_handshake_server(struct tls *ctx)
{
	int ssl_ret;
	int rv = -1;

	if ((ctx->flags & TLS_SERVER_CONN) == 0) {
		tls_set_errorx(ctx, "not a server connection context");
		goto err;
	}

	ERR_clear_error();
	if ((ssl_ret = SSL_accept(ctx->ssl_conn)) != 1) {
		rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "handshake");
		goto err;
	}

	ctx->state |= TLS_HANDSHAKE_COMPLETE;
	rv = 0;

 err:
	return (rv);
}
Exemplo n.º 29
0
/* See RFC 5280 section 4.2.1.6 for SubjectAltName details. */
static int
tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name)
{
	STACK_OF(GENERAL_NAME) *altname_stack = NULL;
	union tls_addr addrbuf;
	int addrlen, type;
	int count, i;
	int rv = -1;

	altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name,
	    NULL, NULL);
	if (altname_stack == NULL)
		return -1;

	if (inet_pton(AF_INET, name, &addrbuf) == 1) {
		type = GEN_IPADD;
		addrlen = 4;
	} else if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
		type = GEN_IPADD;
		addrlen = 16;
	} else {
		type = GEN_DNS;
		addrlen = 0;
	}

	count = sk_GENERAL_NAME_num(altname_stack);
	for (i = 0; i < count; i++) {
		GENERAL_NAME	*altname;

		altname = sk_GENERAL_NAME_value(altname_stack, i);

		if (altname->type != type)
			continue;

		if (type == GEN_DNS) {
			const void	*data;
			int		 format, len;

			format = ASN1_STRING_type(altname->d.dNSName);
			if (format == V_ASN1_IA5STRING) {
				data = ASN1_STRING_get0_data(altname->d.dNSName);
				len = ASN1_STRING_length(altname->d.dNSName);

				if (len < 0 || len != (int)strlen(data)) {
					tls_set_errorx(ctx,
					    "error verifying name '%s': "
					    "NUL byte in subjectAltName, "
					    "probably a malicious certificate",
					    name);
					rv = -2;
					break;
				}

				/*
				 * Per RFC 5280 section 4.2.1.6:
				 * " " is a legal domain name, but that
				 * dNSName must be rejected.
				 */
				if (strcmp(data, " ") == 0) {
					tls_set_error(ctx,
					    "error verifying name '%s': "
					    "a dNSName of \" \" must not be "
					    "used", name);
					rv = -2;
					break;
				}

				if (tls_match_name(data, name) == 0) {
					rv = 0;
					break;
				}
			} else {
#ifdef DEBUG
				fprintf(stdout, "%s: unhandled subjectAltName "
				    "dNSName encoding (%d)\n", getprogname(),
				    format);
#endif
			}

		} else if (type == GEN_IPADD) {
			const unsigned char *data;
			int		 datalen;

			datalen = ASN1_STRING_length(altname->d.iPAddress);
			data = ASN1_STRING_get0_data(altname->d.iPAddress);

			if (datalen < 0) {
				tls_set_errorx(ctx,
				    "Unexpected negative length for an "
				    "IP address: %d", datalen);
				rv = -2;
				break;
			}

			/*
			 * Per RFC 5280 section 4.2.1.6:
			 * IPv4 must use 4 octets and IPv6 must use 16 octets.
			 */
			if (datalen == addrlen &&
			    memcmp(data, &addrbuf, addrlen) == 0) {
				rv = 0;
				break;
			}
		}
	}

	sk_GENERAL_NAME_pop_free(altname_stack, GENERAL_NAME_free);
	return rv;
}
Exemplo n.º 30
0
/* Convert ASN1_TIME to ISO 8601 string */
static int
tls_parse_time(struct tls *ctx, const ASN1_TIME *asn1time, const char **dst_p)
{
	static const char months[12][4] = {
		"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
	};
	char buf[128], *tmp, *mon, *day, *time, *year, *tz;
	char buf2[128];
	BIO *bio;
	int ret, i;

	*dst_p = NULL;

	memset(buf, 0, sizeof buf);
	bio = BIO_new(BIO_s_mem());
	if (!bio)
		goto nomem;

	/* result: Aug 18 20:51:52 2015 GMT */
	ret = ASN1_TIME_print(bio, asn1time);
	if (!ret) {
		BIO_free(bio);
		goto invalid;
	}
	BIO_read(bio, buf, sizeof(buf) - 1);
	BIO_free(bio);
	memcpy(buf2, buf, 128);

	/* "Jan  1" */
	if (buf[3] == ' ' && buf[4] == ' ')
		buf[4] = '0';

	tmp = buf;
	mon = strsep(&tmp, " ");
	day = strsep(&tmp, " ");
	time = strsep(&tmp, " ");
	year = strsep(&tmp, " ");
	tz = strsep(&tmp, " ");

	if (!year || tmp)
		goto invalid;
	if (tz && strcmp(tz, "GMT") != 0)
		goto invalid;

	for (i = 0; i < 12; i++) {
		if (memcmp(months[i], mon, 4) == 0)
			break;
	}
	if (i > 11)
		goto invalid;

	ret = asprintf(&tmp, "%s-%02d-%sT%sZ", year, i+1, day, time);
	if (ret < 0)
		goto nomem;
	*dst_p = tmp;
	return 0;
invalid:
	tls_set_errorx(ctx, "invalid time format");
	return -1;
nomem:
	tls_set_error(ctx, "no mem");
	return -1;
}