1189251Ssam/*
2252726Srpaulo * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
3252726Srpaulo * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#include "common.h"
12214734Srpaulo#include "crypto/sha1.h"
13214734Srpaulo#include "crypto/tls.h"
14189251Ssam#include "tlsv1_common.h"
15189251Ssam#include "tlsv1_record.h"
16189251Ssam#include "tlsv1_server.h"
17189251Ssam#include "tlsv1_server_i.h"
18189251Ssam
19189251Ssam/* TODO:
20189251Ssam * Support for a message fragmented across several records (RFC 2246, 6.2.1)
21189251Ssam */
22189251Ssam
23189251Ssam
24189251Ssamvoid tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
25189251Ssam{
26189251Ssam	conn->alert_level = level;
27189251Ssam	conn->alert_description = description;
28189251Ssam}
29189251Ssam
30189251Ssam
31189251Ssamint tlsv1_server_derive_keys(struct tlsv1_server *conn,
32189251Ssam			     const u8 *pre_master_secret,
33189251Ssam			     size_t pre_master_secret_len)
34189251Ssam{
35189251Ssam	u8 seed[2 * TLS_RANDOM_LEN];
36189251Ssam	u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
37189251Ssam	u8 *pos;
38189251Ssam	size_t key_block_len;
39189251Ssam
40189251Ssam	if (pre_master_secret) {
41189251Ssam		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
42189251Ssam				pre_master_secret, pre_master_secret_len);
43189251Ssam		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
44189251Ssam		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
45189251Ssam			  TLS_RANDOM_LEN);
46252726Srpaulo		if (tls_prf(conn->rl.tls_version,
47252726Srpaulo			    pre_master_secret, pre_master_secret_len,
48189251Ssam			    "master secret", seed, 2 * TLS_RANDOM_LEN,
49189251Ssam			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
50189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
51189251Ssam				   "master_secret");
52189251Ssam			return -1;
53189251Ssam		}
54189251Ssam		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
55189251Ssam				conn->master_secret, TLS_MASTER_SECRET_LEN);
56189251Ssam	}
57189251Ssam
58189251Ssam	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
59189251Ssam	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
60189251Ssam	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
61189251Ssam			     conn->rl.iv_size);
62252726Srpaulo	if (tls_prf(conn->rl.tls_version,
63252726Srpaulo		    conn->master_secret, TLS_MASTER_SECRET_LEN,
64189251Ssam		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
65189251Ssam		    key_block, key_block_len)) {
66189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
67189251Ssam		return -1;
68189251Ssam	}
69189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
70189251Ssam			key_block, key_block_len);
71189251Ssam
72189251Ssam	pos = key_block;
73189251Ssam
74189251Ssam	/* client_write_MAC_secret */
75189251Ssam	os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
76189251Ssam	pos += conn->rl.hash_size;
77189251Ssam	/* server_write_MAC_secret */
78189251Ssam	os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
79189251Ssam	pos += conn->rl.hash_size;
80189251Ssam
81189251Ssam	/* client_write_key */
82189251Ssam	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
83189251Ssam	pos += conn->rl.key_material_len;
84189251Ssam	/* server_write_key */
85189251Ssam	os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
86189251Ssam	pos += conn->rl.key_material_len;
87189251Ssam
88189251Ssam	/* client_write_IV */
89189251Ssam	os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
90189251Ssam	pos += conn->rl.iv_size;
91189251Ssam	/* server_write_IV */
92189251Ssam	os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
93189251Ssam	pos += conn->rl.iv_size;
94189251Ssam
95189251Ssam	return 0;
96189251Ssam}
97189251Ssam
98189251Ssam
99189251Ssam/**
100189251Ssam * tlsv1_server_handshake - Process TLS handshake
101189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
102189251Ssam * @in_data: Input data from TLS peer
103189251Ssam * @in_len: Input data length
104189251Ssam * @out_len: Length of the output buffer.
105189251Ssam * Returns: Pointer to output data, %NULL on failure
106189251Ssam */
107189251Ssamu8 * tlsv1_server_handshake(struct tlsv1_server *conn,
108189251Ssam			    const u8 *in_data, size_t in_len,
109189251Ssam			    size_t *out_len)
110189251Ssam{
111189251Ssam	const u8 *pos, *end;
112189251Ssam	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
113189251Ssam	size_t in_msg_len;
114252726Srpaulo	int used;
115189251Ssam
116189251Ssam	if (in_data == NULL || in_len == 0) {
117189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
118189251Ssam		return NULL;
119189251Ssam	}
120189251Ssam
121189251Ssam	pos = in_data;
122189251Ssam	end = in_data + in_len;
123189251Ssam	in_msg = os_malloc(in_len);
124189251Ssam	if (in_msg == NULL)
125189251Ssam		return NULL;
126189251Ssam
127189251Ssam	/* Each received packet may include multiple records */
128189251Ssam	while (pos < end) {
129189251Ssam		in_msg_len = in_len;
130252726Srpaulo		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
131252726Srpaulo					    in_msg, &in_msg_len, &alert);
132252726Srpaulo		if (used < 0) {
133189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
134189251Ssam				   "record failed");
135189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
136189251Ssam			goto failed;
137189251Ssam		}
138252726Srpaulo		if (used == 0) {
139252726Srpaulo			/* need more data */
140252726Srpaulo			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
141252726Srpaulo				   "yet supported");
142252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
143252726Srpaulo			goto failed;
144252726Srpaulo		}
145189251Ssam		ct = pos[0];
146189251Ssam
147189251Ssam		in_pos = in_msg;
148189251Ssam		in_end = in_msg + in_msg_len;
149189251Ssam
150189251Ssam		/* Each received record may include multiple messages of the
151189251Ssam		 * same ContentType. */
152189251Ssam		while (in_pos < in_end) {
153189251Ssam			in_msg_len = in_end - in_pos;
154189251Ssam			if (tlsv1_server_process_handshake(conn, ct, in_pos,
155189251Ssam							   &in_msg_len) < 0)
156189251Ssam				goto failed;
157189251Ssam			in_pos += in_msg_len;
158189251Ssam		}
159189251Ssam
160252726Srpaulo		pos += used;
161189251Ssam	}
162189251Ssam
163189251Ssam	os_free(in_msg);
164189251Ssam	in_msg = NULL;
165189251Ssam
166189251Ssam	msg = tlsv1_server_handshake_write(conn, out_len);
167189251Ssam
168189251Ssamfailed:
169189251Ssam	os_free(in_msg);
170189251Ssam	if (conn->alert_level) {
171189251Ssam		if (conn->state == FAILED) {
172189251Ssam			/* Avoid alert loops */
173189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop");
174189251Ssam			os_free(msg);
175189251Ssam			return NULL;
176189251Ssam		}
177189251Ssam		conn->state = FAILED;
178189251Ssam		os_free(msg);
179189251Ssam		msg = tlsv1_server_send_alert(conn, conn->alert_level,
180189251Ssam					      conn->alert_description,
181189251Ssam					      out_len);
182189251Ssam	}
183189251Ssam
184189251Ssam	return msg;
185189251Ssam}
186189251Ssam
187189251Ssam
188189251Ssam/**
189189251Ssam * tlsv1_server_encrypt - Encrypt data into TLS tunnel
190189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
191189251Ssam * @in_data: Pointer to plaintext data to be encrypted
192189251Ssam * @in_len: Input buffer length
193189251Ssam * @out_data: Pointer to output buffer (encrypted TLS data)
194189251Ssam * @out_len: Maximum out_data length
195189251Ssam * Returns: Number of bytes written to out_data, -1 on failure
196189251Ssam *
197189251Ssam * This function is used after TLS handshake has been completed successfully to
198189251Ssam * send data in the encrypted tunnel.
199189251Ssam */
200189251Ssamint tlsv1_server_encrypt(struct tlsv1_server *conn,
201189251Ssam			 const u8 *in_data, size_t in_len,
202189251Ssam			 u8 *out_data, size_t out_len)
203189251Ssam{
204189251Ssam	size_t rlen;
205189251Ssam
206189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
207189251Ssam			in_data, in_len);
208189251Ssam
209189251Ssam	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
210252726Srpaulo			      out_data, out_len, in_data, in_len, &rlen) < 0) {
211189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
212189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
213189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
214189251Ssam		return -1;
215189251Ssam	}
216189251Ssam
217189251Ssam	return rlen;
218189251Ssam}
219189251Ssam
220189251Ssam
221189251Ssam/**
222189251Ssam * tlsv1_server_decrypt - Decrypt data from TLS tunnel
223189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
224189251Ssam * @in_data: Pointer to input buffer (encrypted TLS data)
225189251Ssam * @in_len: Input buffer length
226189251Ssam * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
227189251Ssam * @out_len: Maximum out_data length
228189251Ssam * Returns: Number of bytes written to out_data, -1 on failure
229189251Ssam *
230189251Ssam * This function is used after TLS handshake has been completed successfully to
231189251Ssam * receive data from the encrypted tunnel.
232189251Ssam */
233189251Ssamint tlsv1_server_decrypt(struct tlsv1_server *conn,
234189251Ssam			 const u8 *in_data, size_t in_len,
235189251Ssam			 u8 *out_data, size_t out_len)
236189251Ssam{
237189251Ssam	const u8 *in_end, *pos;
238252726Srpaulo	int used;
239252726Srpaulo	u8 alert, *out_end, *out_pos, ct;
240189251Ssam	size_t olen;
241189251Ssam
242189251Ssam	pos = in_data;
243189251Ssam	in_end = in_data + in_len;
244189251Ssam	out_pos = out_data;
245189251Ssam	out_end = out_data + out_len;
246189251Ssam
247189251Ssam	while (pos < in_end) {
248252726Srpaulo		ct = pos[0];
249252726Srpaulo		olen = out_end - out_pos;
250252726Srpaulo		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
251252726Srpaulo					    out_pos, &olen, &alert);
252252726Srpaulo		if (used < 0) {
253252726Srpaulo			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
254252726Srpaulo				   "failed");
255252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
256252726Srpaulo			return -1;
257252726Srpaulo		}
258252726Srpaulo		if (used == 0) {
259252726Srpaulo			/* need more data */
260252726Srpaulo			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
261252726Srpaulo				   "yet supported");
262252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
263252726Srpaulo			return -1;
264252726Srpaulo		}
265252726Srpaulo
266252726Srpaulo		if (ct == TLS_CONTENT_TYPE_ALERT) {
267252726Srpaulo			if (olen < 2) {
268252726Srpaulo				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
269252726Srpaulo					   "underflow");
270252726Srpaulo				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
271252726Srpaulo						   TLS_ALERT_DECODE_ERROR);
272252726Srpaulo				return -1;
273252726Srpaulo			}
274252726Srpaulo			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
275252726Srpaulo				   out_pos[0], out_pos[1]);
276252726Srpaulo			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
277252726Srpaulo				/* Continue processing */
278252726Srpaulo				pos += used;
279252726Srpaulo				continue;
280252726Srpaulo			}
281252726Srpaulo
282252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
283252726Srpaulo					   out_pos[1]);
284252726Srpaulo			return -1;
285252726Srpaulo		}
286252726Srpaulo
287252726Srpaulo		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
288189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
289189251Ssam				   "0x%x", pos[0]);
290189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
291189251Ssam					   TLS_ALERT_UNEXPECTED_MESSAGE);
292189251Ssam			return -1;
293189251Ssam		}
294189251Ssam
295189251Ssam		out_pos += olen;
296189251Ssam		if (out_pos > out_end) {
297189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
298189251Ssam				   "for processing the received record");
299189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
300189251Ssam					   TLS_ALERT_INTERNAL_ERROR);
301189251Ssam			return -1;
302189251Ssam		}
303189251Ssam
304252726Srpaulo		pos += used;
305189251Ssam	}
306189251Ssam
307189251Ssam	return out_pos - out_data;
308189251Ssam}
309189251Ssam
310189251Ssam
311189251Ssam/**
312189251Ssam * tlsv1_server_global_init - Initialize TLSv1 server
313189251Ssam * Returns: 0 on success, -1 on failure
314189251Ssam *
315189251Ssam * This function must be called before using any other TLSv1 server functions.
316189251Ssam */
317189251Ssamint tlsv1_server_global_init(void)
318189251Ssam{
319189251Ssam	return crypto_global_init();
320189251Ssam}
321189251Ssam
322189251Ssam
323189251Ssam/**
324189251Ssam * tlsv1_server_global_deinit - Deinitialize TLSv1 server
325189251Ssam *
326189251Ssam * This function can be used to deinitialize the TLSv1 server that was
327189251Ssam * initialized by calling tlsv1_server_global_init(). No TLSv1 server functions
328189251Ssam * can be called after this before calling tlsv1_server_global_init() again.
329189251Ssam */
330189251Ssamvoid tlsv1_server_global_deinit(void)
331189251Ssam{
332189251Ssam	crypto_global_deinit();
333189251Ssam}
334189251Ssam
335189251Ssam
336189251Ssam/**
337189251Ssam * tlsv1_server_init - Initialize TLSv1 server connection
338189251Ssam * @cred: Pointer to server credentials from tlsv1_server_cred_alloc()
339189251Ssam * Returns: Pointer to TLSv1 server connection data or %NULL on failure
340189251Ssam */
341189251Ssamstruct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
342189251Ssam{
343189251Ssam	struct tlsv1_server *conn;
344189251Ssam	size_t count;
345189251Ssam	u16 *suites;
346189251Ssam
347189251Ssam	conn = os_zalloc(sizeof(*conn));
348189251Ssam	if (conn == NULL)
349189251Ssam		return NULL;
350189251Ssam
351189251Ssam	conn->cred = cred;
352189251Ssam
353189251Ssam	conn->state = CLIENT_HELLO;
354189251Ssam
355189251Ssam	if (tls_verify_hash_init(&conn->verify) < 0) {
356189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
357189251Ssam			   "hash");
358189251Ssam		os_free(conn);
359189251Ssam		return NULL;
360189251Ssam	}
361189251Ssam
362189251Ssam	count = 0;
363189251Ssam	suites = conn->cipher_suites;
364189251Ssam	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
365189251Ssam	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
366189251Ssam	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
367189251Ssam	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
368189251Ssam	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
369189251Ssam	conn->num_cipher_suites = count;
370189251Ssam
371189251Ssam	return conn;
372189251Ssam}
373189251Ssam
374189251Ssam
375189251Ssamstatic void tlsv1_server_clear_data(struct tlsv1_server *conn)
376189251Ssam{
377189251Ssam	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
378189251Ssam	tlsv1_record_change_write_cipher(&conn->rl);
379189251Ssam	tlsv1_record_change_read_cipher(&conn->rl);
380189251Ssam	tls_verify_hash_free(&conn->verify);
381189251Ssam
382189251Ssam	crypto_public_key_free(conn->client_rsa_key);
383189251Ssam	conn->client_rsa_key = NULL;
384189251Ssam
385189251Ssam	os_free(conn->session_ticket);
386189251Ssam	conn->session_ticket = NULL;
387189251Ssam	conn->session_ticket_len = 0;
388189251Ssam	conn->use_session_ticket = 0;
389189251Ssam
390189251Ssam	os_free(conn->dh_secret);
391189251Ssam	conn->dh_secret = NULL;
392189251Ssam	conn->dh_secret_len = 0;
393189251Ssam}
394189251Ssam
395189251Ssam
396189251Ssam/**
397189251Ssam * tlsv1_server_deinit - Deinitialize TLSv1 server connection
398189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
399189251Ssam */
400189251Ssamvoid tlsv1_server_deinit(struct tlsv1_server *conn)
401189251Ssam{
402189251Ssam	tlsv1_server_clear_data(conn);
403189251Ssam	os_free(conn);
404189251Ssam}
405189251Ssam
406189251Ssam
407189251Ssam/**
408189251Ssam * tlsv1_server_established - Check whether connection has been established
409189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
410189251Ssam * Returns: 1 if connection is established, 0 if not
411189251Ssam */
412189251Ssamint tlsv1_server_established(struct tlsv1_server *conn)
413189251Ssam{
414189251Ssam	return conn->state == ESTABLISHED;
415189251Ssam}
416189251Ssam
417189251Ssam
418189251Ssam/**
419189251Ssam * tlsv1_server_prf - Use TLS-PRF to derive keying material
420189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
421189251Ssam * @label: Label (e.g., description of the key) for PRF
422189251Ssam * @server_random_first: seed is 0 = client_random|server_random,
423189251Ssam * 1 = server_random|client_random
424189251Ssam * @out: Buffer for output data from TLS-PRF
425189251Ssam * @out_len: Length of the output buffer
426189251Ssam * Returns: 0 on success, -1 on failure
427189251Ssam */
428189251Ssamint tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
429189251Ssam		     int server_random_first, u8 *out, size_t out_len)
430189251Ssam{
431189251Ssam	u8 seed[2 * TLS_RANDOM_LEN];
432189251Ssam
433189251Ssam	if (conn->state != ESTABLISHED)
434189251Ssam		return -1;
435189251Ssam
436189251Ssam	if (server_random_first) {
437189251Ssam		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
438189251Ssam		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
439189251Ssam			  TLS_RANDOM_LEN);
440189251Ssam	} else {
441189251Ssam		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
442189251Ssam		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
443189251Ssam			  TLS_RANDOM_LEN);
444189251Ssam	}
445189251Ssam
446252726Srpaulo	return tls_prf(conn->rl.tls_version,
447252726Srpaulo		       conn->master_secret, TLS_MASTER_SECRET_LEN,
448189251Ssam		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
449189251Ssam}
450189251Ssam
451189251Ssam
452189251Ssam/**
453189251Ssam * tlsv1_server_get_cipher - Get current cipher name
454189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
455189251Ssam * @buf: Buffer for the cipher name
456189251Ssam * @buflen: buf size
457189251Ssam * Returns: 0 on success, -1 on failure
458189251Ssam *
459189251Ssam * Get the name of the currently used cipher.
460189251Ssam */
461189251Ssamint tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
462189251Ssam			    size_t buflen)
463189251Ssam{
464189251Ssam	char *cipher;
465189251Ssam
466189251Ssam	switch (conn->rl.cipher_suite) {
467189251Ssam	case TLS_RSA_WITH_RC4_128_MD5:
468189251Ssam		cipher = "RC4-MD5";
469189251Ssam		break;
470189251Ssam	case TLS_RSA_WITH_RC4_128_SHA:
471189251Ssam		cipher = "RC4-SHA";
472189251Ssam		break;
473189251Ssam	case TLS_RSA_WITH_DES_CBC_SHA:
474189251Ssam		cipher = "DES-CBC-SHA";
475189251Ssam		break;
476189251Ssam	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
477189251Ssam		cipher = "DES-CBC3-SHA";
478189251Ssam		break;
479189251Ssam	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
480189251Ssam		cipher = "ADH-AES-128-SHA";
481189251Ssam		break;
482189251Ssam	case TLS_RSA_WITH_AES_256_CBC_SHA:
483189251Ssam		cipher = "AES-256-SHA";
484189251Ssam		break;
485189251Ssam	case TLS_RSA_WITH_AES_128_CBC_SHA:
486189251Ssam		cipher = "AES-128-SHA";
487189251Ssam		break;
488189251Ssam	default:
489189251Ssam		return -1;
490189251Ssam	}
491189251Ssam
492189251Ssam	if (os_strlcpy(buf, cipher, buflen) >= buflen)
493189251Ssam		return -1;
494189251Ssam	return 0;
495189251Ssam}
496189251Ssam
497189251Ssam
498189251Ssam/**
499189251Ssam * tlsv1_server_shutdown - Shutdown TLS connection
500189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
501189251Ssam * Returns: 0 on success, -1 on failure
502189251Ssam */
503189251Ssamint tlsv1_server_shutdown(struct tlsv1_server *conn)
504189251Ssam{
505189251Ssam	conn->state = CLIENT_HELLO;
506189251Ssam
507189251Ssam	if (tls_verify_hash_init(&conn->verify) < 0) {
508189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
509189251Ssam			   "hash");
510189251Ssam		return -1;
511189251Ssam	}
512189251Ssam
513189251Ssam	tlsv1_server_clear_data(conn);
514189251Ssam
515189251Ssam	return 0;
516189251Ssam}
517189251Ssam
518189251Ssam
519189251Ssam/**
520189251Ssam * tlsv1_server_resumed - Was session resumption used
521189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
522189251Ssam * Returns: 1 if current session used session resumption, 0 if not
523189251Ssam */
524189251Ssamint tlsv1_server_resumed(struct tlsv1_server *conn)
525189251Ssam{
526189251Ssam	return 0;
527189251Ssam}
528189251Ssam
529189251Ssam
530189251Ssam/**
531189251Ssam * tlsv1_server_get_keys - Get master key and random data from TLS connection
532189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
533189251Ssam * @keys: Structure of key/random data (filled on success)
534189251Ssam * Returns: 0 on success, -1 on failure
535189251Ssam */
536189251Ssamint tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
537189251Ssam{
538189251Ssam	os_memset(keys, 0, sizeof(*keys));
539189251Ssam	if (conn->state == CLIENT_HELLO)
540189251Ssam		return -1;
541189251Ssam
542189251Ssam	keys->client_random = conn->client_random;
543189251Ssam	keys->client_random_len = TLS_RANDOM_LEN;
544189251Ssam
545189251Ssam	if (conn->state != SERVER_HELLO) {
546189251Ssam		keys->server_random = conn->server_random;
547189251Ssam		keys->server_random_len = TLS_RANDOM_LEN;
548189251Ssam		keys->master_key = conn->master_secret;
549189251Ssam		keys->master_key_len = TLS_MASTER_SECRET_LEN;
550189251Ssam	}
551189251Ssam
552189251Ssam	return 0;
553189251Ssam}
554189251Ssam
555189251Ssam
556189251Ssam/**
557189251Ssam * tlsv1_server_get_keyblock_size - Get TLS key_block size
558189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
559189251Ssam * Returns: Size of the key_block for the negotiated cipher suite or -1 on
560189251Ssam * failure
561189251Ssam */
562189251Ssamint tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)
563189251Ssam{
564189251Ssam	if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
565189251Ssam		return -1;
566189251Ssam
567189251Ssam	return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
568189251Ssam		    conn->rl.iv_size);
569189251Ssam}
570189251Ssam
571189251Ssam
572189251Ssam/**
573189251Ssam * tlsv1_server_set_cipher_list - Configure acceptable cipher suites
574189251Ssam * @conn: TLSv1 server connection data from tlsv1_server_init()
575189251Ssam * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
576189251Ssam * (TLS_CIPHER_*).
577189251Ssam * Returns: 0 on success, -1 on failure
578189251Ssam */
579189251Ssamint tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)
580189251Ssam{
581189251Ssam	size_t count;
582189251Ssam	u16 *suites;
583189251Ssam
584189251Ssam	/* TODO: implement proper configuration of cipher suites */
585189251Ssam	if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
586189251Ssam		count = 0;
587189251Ssam		suites = conn->cipher_suites;
588189251Ssam		suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
589189251Ssam		suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
590189251Ssam		suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
591189251Ssam		suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
592189251Ssam		suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
593189251Ssam		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
594189251Ssam		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
595189251Ssam		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
596189251Ssam		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
597189251Ssam		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
598189251Ssam		conn->num_cipher_suites = count;
599189251Ssam	}
600189251Ssam
601189251Ssam	return 0;
602189251Ssam}
603189251Ssam
604189251Ssam
605189251Ssamint tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)
606189251Ssam{
607189251Ssam	conn->verify_peer = verify_peer;
608189251Ssam	return 0;
609189251Ssam}
610189251Ssam
611189251Ssam
612189251Ssamvoid tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
613189251Ssam					tlsv1_server_session_ticket_cb cb,
614189251Ssam					void *ctx)
615189251Ssam{
616189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
617189251Ssam		   cb, ctx);
618189251Ssam	conn->session_ticket_cb = cb;
619189251Ssam	conn->session_ticket_cb_ctx = ctx;
620189251Ssam}
621