tls.h 7.24 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*  Copyright (C) 2016 American Civil Liberties Union (ACLU)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <uv.h>
20
#include <gnutls/gnutls.h>
21
#include <libknot/packet/pkt.h>
22
#include "lib/defines.h"
23 24
#include "lib/generic/array.h"
#include "lib/generic/map.h"
25 26

#define MAX_TLS_PADDING KR_EDNS_PAYLOAD
27
#define TLS_MAX_UNCORK_RETRIES 100
28

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
/* rfc 5476, 7.3 - handshake Protocol overview
 * https://tools.ietf.org/html/rfc5246#page-33
 * Message flow for a full handshake (only mandatory messages)
 * ClientHello           -------->
                                        ServerHello
                         <--------      ServerHelloDone
   ClientKeyExchange
   Finished              -------->
                         <--------      Finished
 *
 * See also https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/
 * So it takes 2 RTT.
 * As we use session tickets, there are additional messages, add one RTT mode.
 */
 #define TLS_MAX_HANDSHAKE_TIME (KR_CONN_RTT_MAX * 3)

45 46 47
/** Transport session (opaque). */
struct session;

48
struct tls_ctx_t;
49
struct tls_client_ctx_t;
50
struct tls_credentials {
51 52 53 54
	int count;
	char *tls_cert;
	char *tls_key;
	gnutls_certificate_credentials_t credentials;
55
	time_t valid_until;
56
	char *ephemeral_servicename;
57
};
58

59 60
struct tls_client_paramlist_entry {
	array_t(const char *) ca_files;
61
	array_t(const char *) hostnames;
62 63
	array_t(const char *) pins;
	gnutls_certificate_credentials_t credentials;
64
	gnutls_datum_t session_data;
65
	uint32_t refs;
66 67
};

68 69 70
struct worker_ctx;
struct qr_task;

71 72 73
typedef enum tls_client_hs_state {
	TLS_HS_NOT_STARTED = 0,
	TLS_HS_IN_PROGRESS,
74
	TLS_HS_DONE,
75
	TLS_HS_CLOSING,
76
	TLS_HS_LAST
77
} tls_hs_state_t;
78 79 80

typedef int (*tls_handshake_cb) (struct session *session, int status);

81 82 83 84 85 86 87
typedef enum tls_client_param {
	TLS_CLIENT_PARAM_NONE = 0,
	TLS_CLIENT_PARAM_PIN,
	TLS_CLIENT_PARAM_HOSTNAME,
	TLS_CLIENT_PARAM_CA,
} tls_client_param_t;

88 89
struct tls_common_ctx {
	bool client_side;
90
	gnutls_session_t tls_session;
91
	tls_hs_state_t handshake_state;
92
	struct session *session;
93
	/* for reading from the network */
94 95 96
	const uint8_t *buf;
	ssize_t nread;
	ssize_t consumed;
97
	uint8_t recv_buf[8192];
98
	tls_handshake_cb handshake_cb;
99
	struct worker_ctx *worker;
100
	size_t write_queue_size;
101 102
};

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
struct tls_ctx_t {
	/*
	 * Since pointer to tls_ctx_t needs to be casted
	 * to  tls_ctx_common in some functions,
	 * this field must be always at first position
	 */
	struct tls_common_ctx c;
	struct tls_credentials *credentials;
};

struct tls_client_ctx_t {
	/*
	 * Since pointer to tls_client_ctx_t needs to be casted
	 * to  tls_ctx_common in some functions,
	 * this field must be always at first position
	 */
	struct tls_common_ctx c;
120
	struct tls_client_paramlist_entry *params;
121 122
};

123
/*! Create an empty TLS context in query context */
124
struct tls_ctx_t* tls_new(struct worker_ctx *worker);
125

126
/*! Close a TLS context (call gnutls_bye()) */
127
void tls_close(struct tls_common_ctx *ctx);
128 129

/*! Release a TLS context */
130 131
void tls_free(struct tls_ctx_t* tls);

132
/*! Push new data to TLS context for sending */
133
int tls_write(uv_write_t *req, uv_handle_t* handle, knot_pkt_t * pkt, uv_write_cb cb);
134

135 136 137
/*! Unwrap incoming data from a TLS stream and pass them to TCP session.
 * @return the number of newly-completed requests (>=0) or an error code
 */
138
ssize_t tls_process_input_data(struct session *s, const uint8_t *buf, ssize_t nread);
139

140
/*! Set TLS certificate and key from files. */
141
int tls_certificate_set(struct network *net, const char *tls_cert, const char *tls_key);
142 143

/*! Borrow TLS credentials for context. */
144
struct tls_credentials *tls_credentials_reserve(struct tls_credentials *tls_credentials);
145 146

/*! Release TLS credentials for context (decrements refcount or frees). */
147
int tls_credentials_release(struct tls_credentials *tls_credentials);
148 149

/*! Free TLS credentials, must not be called if it holds positive refcount. */
150
void tls_credentials_free(struct tls_credentials *tls_credentials);
151 152

/*! Log DNS-over-TLS OOB key-pin form of current credentials:
153 154
 * https://tools.ietf.org/html/rfc7858#appendix-A */
void tls_credentials_log_pins(struct tls_credentials *tls_credentials);
155 156 157

/*! Generate new ephemeral TLS credentials. */
struct tls_credentials * tls_get_ephemeral_credentials(struct engine *engine);
158

159 160 161 162 163 164
/*! Get TLS handshake state. */
tls_hs_state_t tls_get_hs_state(const struct tls_common_ctx *ctx);

/*! Set TLS handshake state. */
int tls_set_hs_state(struct tls_common_ctx *ctx, tls_hs_state_t state);

165 166 167 168 169 170
/*! Find TLS parameters for given address. Attempt opportunistic upgrade for port 53 to 853,
 *  if the address is configured with a working DoT on port 853.
 */
struct tls_client_paramlist_entry *tls_client_try_upgrade(map_t *tls_client_paramlist,
			  const struct sockaddr *addr);

171 172 173 174
/*! Set TLS authentication parameters for given address.
 * Note: hostnames must be imported before ca files,
 *       otherwise ca files will not be imported at all.
 */
175 176
int tls_client_params_set(map_t *tls_client_paramlist,
			  const char *addr, uint16_t port,
177
			  const char *param, tls_client_param_t param_type);
178 179 180 181 182

/*! Free TLS authentication parameters. */
int tls_client_params_free(map_t *tls_client_paramlist);

/*! Allocate new client TLS context */
183
struct tls_client_ctx_t *tls_client_ctx_new(struct tls_client_paramlist_entry *entry,
184
					    struct worker_ctx *worker);
185 186 187 188

/*! Free client TLS context */
void tls_client_ctx_free(struct tls_client_ctx_t *ctx);

189 190
int tls_client_connect_start(struct tls_client_ctx_t *client_ctx,
			     struct session *session,
191 192
			     tls_handshake_cb handshake_cb);

193
int tls_client_ctx_set_session(struct tls_client_ctx_t *ctx, struct session *session);
194

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

/* Session tickets, server side.  Implementation in ./tls_session_ticket-srv.c */

/*! Opaque struct used by tls_session_ticket_* functions. */
struct tls_session_ticket_ctx;

/*! Suggested maximum reasonable secret length. */
#define TLS_SESSION_TICKET_SECRET_MAX_LEN 1024

/*! Create a session ticket context and initialize it (secret gets copied inside).
 *
 * Passing zero-length secret implies using a random key, i.e. not synchronized
 * between multiple instances.
 *
 * Beware that knowledge of the secret (if nonempty) breaks forward secrecy,
 * so you should rotate the secret regularly and securely erase all past secrets.
 * With TLS < 1.3 it's probably too risky to set nonempty secret.
 */
struct tls_session_ticket_ctx * tls_session_ticket_ctx_create(
		uv_loop_t *loop, const char *secret, size_t secret_len);

/*! Try to enable session tickets for a server session. */
void tls_session_ticket_enable(struct tls_session_ticket_ctx *ctx, gnutls_session_t session);

/*! Free all resources of the session ticket context.  NULL is accepted as well. */
220
void tls_session_ticket_ctx_destroy(struct tls_session_ticket_ctx *ctx);
221