Exemplo n.º 1
0
int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
				 const u8 *server_random,
				 const u8 *server_params,
				 size_t server_params_len, u8 *hash)
{
	u8 *hpos;
	size_t hlen;
	struct crypto_hash *ctx;

	hpos = hash;

	ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
	if (ctx == NULL)
		return -1;
	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
	crypto_hash_update(ctx, server_params, server_params_len);
	hlen = MD5_MAC_LEN;
	if (crypto_hash_finish(ctx, hash, &hlen) < 0)
		return -1;
	hpos += hlen;

	ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
	if (ctx == NULL)
		return -1;
	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
	crypto_hash_update(ctx, server_params, server_params_len);
	hlen = hash + sizeof(hash) - hpos;
	if (crypto_hash_finish(ctx, hpos, &hlen) < 0)
		return -1;
	hpos += hlen;
	return hpos - hash;
}
void tls_verify_hash_free(struct tls_verify_hash *verify)
{
	crypto_hash_finish(verify->md5_client, NULL, NULL);
	crypto_hash_finish(verify->md5_server, NULL, NULL);
	crypto_hash_finish(verify->md5_cert, NULL, NULL);
	crypto_hash_finish(verify->sha1_client, NULL, NULL);
	crypto_hash_finish(verify->sha1_server, NULL, NULL);
	crypto_hash_finish(verify->sha1_cert, NULL, NULL);
	verify->md5_client = NULL;
	verify->md5_server = NULL;
	verify->md5_cert = NULL;
	verify->sha1_client = NULL;
	verify->sha1_server = NULL;
	verify->sha1_cert = NULL;
#ifdef CONFIG_TLSV12
	crypto_hash_finish(verify->sha256_client, NULL, NULL);
	crypto_hash_finish(verify->sha256_server, NULL, NULL);
	crypto_hash_finish(verify->sha256_cert, NULL, NULL);
	verify->sha256_client = NULL;
	verify->sha256_server = NULL;
	verify->sha256_cert = NULL;
#endif /* CONFIG_TLSV12 */
}
Exemplo n.º 3
0
/* a counter-based KDF based on NIST SP800-108 */
static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label, size_t labellen, u8 *result, size_t resultbitlen)
{
	struct crypto_hash *hash;
	u8 digest[SHA256_MAC_LEN];
	u16 i, ctr, L;
	size_t resultbytelen, len = 0, mdlen;

	resultbytelen = (resultbitlen + 7) / 8;
	ctr = 0;
	L = htons(resultbitlen);
	while (len < resultbytelen) {
		ctr++;
		i = htons(ctr);
		hash = crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256, key, keylen);
		if (hash == NULL) {
			return -1;
		}
		if (ctr > 1) {
			crypto_hash_update(hash, digest, SHA256_MAC_LEN);
		}
		crypto_hash_update(hash, (u8 *)&i, sizeof(u16));
		crypto_hash_update(hash, label, labellen);
		crypto_hash_update(hash, (u8 *)&L, sizeof(u16));
		mdlen = SHA256_MAC_LEN;
		if (crypto_hash_finish(hash, digest, &mdlen) < 0) {
			return -1;
		}
		if ((len + mdlen) > resultbytelen) {
			os_memcpy(result + len, digest, resultbytelen - len);
		} else {
			os_memcpy(result + len, digest, mdlen);
		}
		len += mdlen;
	}

	/* since we're expanding to a bit length, mask off the excess */
	if (resultbitlen % 8) {
		u8 mask = 0xff;
		mask <<= (8 - (resultbitlen % 8));
		result[resultbytelen - 1] &= mask;
	}

	return 0;
}
Exemplo n.º 4
0
int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_alg,
				    const u8 *client_random,
				    const u8 *server_random,
				    const u8 *server_params,
				    size_t server_params_len, u8 *hash)
{
	size_t hlen;
	struct crypto_hash *ctx;
	enum crypto_hash_alg alg;

	switch (hash_alg) {
	case TLS_HASH_ALG_SHA256:
		alg = CRYPTO_HASH_ALG_SHA256;
		hlen = SHA256_MAC_LEN;
		break;
	case TLS_HASH_ALG_SHA384:
		alg = CRYPTO_HASH_ALG_SHA384;
		hlen = 48;
		break;
	case TLS_HASH_ALG_SHA512:
		alg = CRYPTO_HASH_ALG_SHA512;
		hlen = 64;
		break;
	default:
		return -1;
	}
	ctx = crypto_hash_init(alg, NULL, 0);
	if (ctx == NULL)
		return -1;
	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
	crypto_hash_update(ctx, server_params, server_params_len);
	if (crypto_hash_finish(ctx, hash, &hlen) < 0)
		return -1;

	return hlen;
}
Exemplo n.º 5
0
static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
        const u8 *in_data, size_t *in_len) {
    const u8 *pos, *end;
    size_t left, len, hlen;
    u8 verify_data[TLS_VERIFY_DATA_LEN];
    u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];

    if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
        wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
                "received content type 0x%x", ct);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_UNEXPECTED_MESSAGE);
        return -1;
    }

    pos = in_data;
    left = *in_len;

    if (left < 4) {
        wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
                "Finished",
                (unsigned long) left);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }

    if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
        wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
                "type 0x%x", pos[0]);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_UNEXPECTED_MESSAGE);
        return -1;
    }

    len = WPA_GET_BE24(pos + 1);

    pos += 4;
    left -= 4;

    if (len > left) {
        wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
                "(len=%lu > left=%lu)",
                (unsigned long) len, (unsigned long) left);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }
    end = pos + len;
    if (len != TLS_VERIFY_DATA_LEN) {
        wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
                "in Finished: %lu (expected %d)",
                (unsigned long) len, TLS_VERIFY_DATA_LEN);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }
    wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
            pos, TLS_VERIFY_DATA_LEN);

    hlen = MD5_MAC_LEN;
    if (conn->verify.md5_client == NULL ||
            crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        conn->verify.md5_client = NULL;
        crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
        conn->verify.sha1_client = NULL;
        return -1;
    }
    conn->verify.md5_client = NULL;
    hlen = SHA1_MAC_LEN;
    if (conn->verify.sha1_client == NULL ||
            crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
            &hlen) < 0) {
        conn->verify.sha1_client = NULL;
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }
    conn->verify.sha1_client = NULL;

    if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
            "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
            verify_data, TLS_VERIFY_DATA_LEN)) {
        wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECRYPT_ERROR);
        return -1;
    }
    wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
            verify_data, TLS_VERIFY_DATA_LEN);

    if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
        wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
        return -1;
    }

    wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");

    *in_len = end - in_data;

    if (conn->use_session_ticket) {
        /* Abbreviated handshake using session ticket; RFC 4507 */
        wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
                "successfully");
        conn->state = ESTABLISHED;
    } else {
        /* Full handshake */
        conn->state = SERVER_CHANGE_CIPHER_SPEC;
    }

    return 0;
}
Exemplo n.º 6
0
static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
        const u8 *in_data, size_t *in_len) {
    const u8 *pos, *end;
    size_t left, len;
    u8 type;
    size_t hlen, buflen;
    u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;

    enum {
        SIGN_ALG_RSA, SIGN_ALG_DSA
    } alg = SIGN_ALG_RSA;
    u16 slen;

    if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
        if (conn->verify_peer) {
            wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
                    "CertificateVerify");
            tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                    TLS_ALERT_UNEXPECTED_MESSAGE);
            return -1;
        }

        return tls_process_change_cipher_spec(conn, ct, in_data,
                in_len);
    }

    if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
        wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
                "received content type 0x%x", ct);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_UNEXPECTED_MESSAGE);
        return -1;
    }

    pos = in_data;
    left = *in_len;

    if (left < 4) {
        wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
                "message (len=%lu)", (unsigned long) left);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }

    type = *pos++;
    len = WPA_GET_BE24(pos);
    pos += 3;
    left -= 4;

    if (len > left) {
        wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
                "message length (len=%lu != left=%lu)",
                (unsigned long) len, (unsigned long) left);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }

    end = pos + len;

    if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
        wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
                "message %d (expected CertificateVerify)", type);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_UNEXPECTED_MESSAGE);
        return -1;
    }

    wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");

    /*
     * struct {
     *   Signature signature;
     * } CertificateVerify;
     */

    hpos = hash;

    if (alg == SIGN_ALG_RSA) {
        hlen = MD5_MAC_LEN;
        if (conn->verify.md5_cert == NULL ||
                crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
            tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                    TLS_ALERT_INTERNAL_ERROR);
            conn->verify.md5_cert = NULL;
            crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
            conn->verify.sha1_cert = NULL;
            return -1;
        }
        hpos += MD5_MAC_LEN;
    } else
        crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);

    conn->verify.md5_cert = NULL;
    hlen = SHA1_MAC_LEN;
    if (conn->verify.sha1_cert == NULL ||
            crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
        conn->verify.sha1_cert = NULL;
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }
    conn->verify.sha1_cert = NULL;

    if (alg == SIGN_ALG_RSA)
        hlen += MD5_MAC_LEN;

    wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);

    if (end - pos < 2) {
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }
    slen = WPA_GET_BE16(pos);
    pos += 2;
    if (end - pos < slen) {
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }

    wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
    if (conn->client_rsa_key == NULL) {
        wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
                "signature");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    buflen = end - pos;
    buf = os_malloc(end - pos);
    if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
            pos, end - pos, buf, &buflen) < 0) {
        wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
        os_free(buf);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECRYPT_ERROR);
        return -1;
    }

    wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
            buf, buflen);

    if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
        wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
                "CertificateVerify - did not match with calculated "
                "hash");
        os_free(buf);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECRYPT_ERROR);
        return -1;
    }

    os_free(buf);

    *in_len = end - in_data;

    conn->state = CHANGE_CIPHER_SPEC;

    return 0;
}
static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
				       const u8 *in_data, size_t *in_len)
{
	const u8 *pos, *end;
	size_t left, len, hlen;
	u8 verify_data[TLS_VERIFY_DATA_LEN];
	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];

	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
			   "received content type 0x%x", ct);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_UNEXPECTED_MESSAGE);
		return -1;
	}

	pos = in_data;
	left = *in_len;

	if (left < 4) {
		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
			   "Finished",
			   (unsigned long) left);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECODE_ERROR);
		return -1;
	}

	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
			   "type 0x%x", pos[0]);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_UNEXPECTED_MESSAGE);
		return -1;
	}

	len = WPA_GET_BE24(pos + 1);

	pos += 4;
	left -= 4;

	if (len > left) {
		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
			   "(len=%lu > left=%lu)",
			   (unsigned long) len, (unsigned long) left);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECODE_ERROR);
		return -1;
	}
	end = pos + len;
	if (len != TLS_VERIFY_DATA_LEN) {
		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
			   "in Finished: %lu (expected %d)",
			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECODE_ERROR);
		return -1;
	}
	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
		    pos, TLS_VERIFY_DATA_LEN);

#ifdef CONFIG_TLSV12
	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
		hlen = SHA256_MAC_LEN;
		if (conn->verify.sha256_server == NULL ||
		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
		    < 0) {
			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
				  TLS_ALERT_INTERNAL_ERROR);
			conn->verify.sha256_server = NULL;
			return -1;
		}
		conn->verify.sha256_server = NULL;
	} else {
#endif /* CONFIG_TLSV12 */

	hlen = MD5_MAC_LEN;
	if (conn->verify.md5_server == NULL ||
	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		conn->verify.md5_server = NULL;
		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
		conn->verify.sha1_server = NULL;
		return -1;
	}
	conn->verify.md5_server = NULL;
	hlen = SHA1_MAC_LEN;
	if (conn->verify.sha1_server == NULL ||
	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
			       &hlen) < 0) {
		conn->verify.sha1_server = NULL;
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	conn->verify.sha1_server = NULL;
	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;

#ifdef CONFIG_TLSV12
	}
#endif /* CONFIG_TLSV12 */

	if (tls_prf(conn->rl.tls_version,
		    conn->master_secret, TLS_MASTER_SECRET_LEN,
		    "server finished", hash, hlen,
		    verify_data, TLS_VERIFY_DATA_LEN)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECRYPT_ERROR);
		return -1;
	}
	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
			verify_data, TLS_VERIFY_DATA_LEN);

	if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECRYPT_ERROR);
		return -1;
	}

	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");

	*in_len = end - in_data;

	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
		CHANGE_CIPHER_SPEC : ACK_FINISHED;

	return 0;
}
Exemplo n.º 8
0
/**
 * tlsv1_record_receive - TLS record layer: Process a received message
 * @rl: Pointer to TLS record layer data
 * @in_data: Received data
 * @in_len: Length of the received data
 * @out_data: Buffer for output data (must be at least as long as in_data)
 * @out_len: Set to maximum out_data length by caller; used to return the
 * length of the used data
 * @alert: Buffer for returning an alert value on failure
 * Returns: 0 on success, -1 on failure
 *
 * This function decrypts the received message, verifies HMAC and TLS record
 * layer header.
 */
int tlsv1_record_receive(struct tlsv1_record_layer *rl,
			 const u8 *in_data, size_t in_len,
			 u8 *out_data, size_t *out_len, u8 *alert)
{
	size_t i, rlen, hlen;
	u8 padlen;
	struct crypto_hash *hmac;
	u8 len[2], hash[100];

	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
		    in_data, in_len);

	if (in_len < TLS_RECORD_HEADER_LEN) {
		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
			   (unsigned long) in_len);
		*alert = TLS_ALERT_DECODE_ERROR;
		return -1;
	}

	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
		   "length %d", in_data[0], in_data[1], in_data[2],
		   WPA_GET_BE16(in_data + 3));

	if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
	    in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
	    in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
			   in_data[0]);
		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
		return -1;
	}

	if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
			   "%d.%d", in_data[1], in_data[2]);
		*alert = TLS_ALERT_PROTOCOL_VERSION;
		return -1;
	}

	rlen = WPA_GET_BE16(in_data + 3);

	/* TLSCiphertext must not be more than 2^14+2048 bytes */
	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
			   (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
		*alert = TLS_ALERT_RECORD_OVERFLOW;
		return -1;
	}

	in_data += TLS_RECORD_HEADER_LEN;
	in_len -= TLS_RECORD_HEADER_LEN;

	if (rlen > in_len) {
		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
			   "(rlen=%lu > in_len=%lu)",
			   (unsigned long) rlen, (unsigned long) in_len);
		*alert = TLS_ALERT_DECODE_ERROR;
		return -1;
	}

	in_len = rlen;

	if (*out_len < in_len) {
		wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
			   "processing received record");
		*alert = TLS_ALERT_INTERNAL_ERROR;
		return -1;
	}

	os_memcpy(out_data, in_data, in_len);
	*out_len = in_len;

	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
		if (crypto_cipher_decrypt(rl->read_cbc, out_data,
					  out_data, in_len) < 0) {
			*alert = TLS_ALERT_DECRYPTION_FAILED;
			return -1;
		}
		if (rl->iv_size) {
			if (in_len == 0) {
				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
					   " (no pad)");
				*alert = TLS_ALERT_DECODE_ERROR;
				return -1;
			}
			padlen = out_data[in_len - 1];
			if (padlen >= in_len) {
				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
					   "length (%u, in_len=%lu) in "
					   "received record",
					   padlen, (unsigned long) in_len);
				*alert = TLS_ALERT_DECRYPTION_FAILED;
				return -1;
			}
			for (i = in_len - padlen; i < in_len; i++) {
				if (out_data[i] != padlen) {
					wpa_hexdump(MSG_DEBUG,
						    "TLSv1: Invalid pad in "
						    "received record",
						    out_data + in_len - padlen,
						    padlen);
					*alert = TLS_ALERT_DECRYPTION_FAILED;
					return -1;
				}
			}

			*out_len -= padlen + 1;
		}

		wpa_hexdump(MSG_MSGDUMP,
			    "TLSv1: Record Layer - Decrypted data",
			    out_data, in_len);

		if (*out_len < rl->hash_size) {
			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
				   "hash value");
			*alert = TLS_ALERT_INTERNAL_ERROR;
			return -1;
		}

		*out_len -= rl->hash_size;

		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
					rl->hash_size);
		if (hmac == NULL) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
				   "to initialize HMAC");
			*alert = TLS_ALERT_INTERNAL_ERROR;
			return -1;
		}

		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
		/* type + version + length + fragment */
		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
		WPA_PUT_BE16(len, *out_len);
		crypto_hash_update(hmac, len, 2);
		crypto_hash_update(hmac, out_data, *out_len);
		hlen = sizeof(hash);
		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
				   "to calculate HMAC");
			return -1;
		}
		if (hlen != rl->hash_size ||
		    os_memcmp(hash, out_data + *out_len, hlen) != 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
				   "received message");
			*alert = TLS_ALERT_BAD_RECORD_MAC;
			return -1;
		}
	}

	/* TLSCompressed must not be more than 2^14+1024 bytes */
	if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
			   (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
		*alert = TLS_ALERT_RECORD_OVERFLOW;
		return -1;
	}

	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);

	return 0;
}
Exemplo n.º 9
0
/**
 * tlsv1_record_send - TLS record layer: Send a message
 * @rl: Pointer to TLS record layer data
 * @content_type: Content type (TLS_CONTENT_TYPE_*)
 * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
 * beginning for record layer to fill in; payload filled in after this and
 * extra space in the end for HMAC).
 * @buf_size: Maximum buf size
 * @payload_len: Length of the payload
 * @out_len: Buffer for returning the used buf length
 * Returns: 0 on success, -1 on failure
 *
 * This function fills in the TLS record layer header, adds HMAC, and encrypts
 * the data using the current write cipher.
 */
int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
		      size_t buf_size, size_t payload_len, size_t *out_len)
{
	u8 *pos, *ct_start, *length, *payload;
	struct crypto_hash *hmac;
	size_t clen;

	pos = buf;
	/* ContentType type */
	ct_start = pos;
	*pos++ = content_type;
	/* ProtocolVersion version */
	WPA_PUT_BE16(pos, TLS_VERSION);
	pos += 2;
	/* uint16 length */
	length = pos;
	WPA_PUT_BE16(length, payload_len);
	pos += 2;

	/* opaque fragment[TLSPlaintext.length] */
	payload = pos;
	pos += payload_len;

	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
					rl->hash_size);
		if (hmac == NULL) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
				   "to initialize HMAC");
			return -1;
		}
		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
		/* type + version + length + fragment */
		crypto_hash_update(hmac, ct_start, pos - ct_start);
		clen = buf + buf_size - pos;
		if (clen < rl->hash_size) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
				   "enough room for MAC");
			crypto_hash_finish(hmac, NULL, NULL);
			return -1;
		}

		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
				   "to calculate HMAC");
			return -1;
		}
		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
			    pos, clen);
		pos += clen;
		if (rl->iv_size) {
			size_t len = pos - payload;
			size_t pad;
			pad = (len + 1) % rl->iv_size;
			if (pad)
				pad = rl->iv_size - pad;
			if (pos + pad + 1 > buf + buf_size) {
				wpa_printf(MSG_DEBUG, "TLSv1: No room for "
					   "block cipher padding");
				return -1;
			}
			os_memset(pos, pad, pad + 1);
			pos += pad + 1;
		}

		if (crypto_cipher_encrypt(rl->write_cbc, payload,
					  payload, pos - payload) < 0)
			return -1;
	}

	WPA_PUT_BE16(length, pos - length - 2);
	inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);

	*out_len = pos - buf;

	return 0;
}
Exemplo n.º 10
0
/**
 * tlsv1_record_send - TLS record layer: Send a message
 * @rl: Pointer to TLS record layer data
 * @content_type: Content type (TLS_CONTENT_TYPE_*)
 * @buf: Buffer for the generated TLS message (needs to have extra space for
 * header, IV (TLS v1.1), and HMAC)
 * @buf_size: Maximum buf size
 * @payload: Payload to be sent
 * @payload_len: Length of the payload
 * @out_len: Buffer for returning the used buf length
 * Returns: 0 on success, -1 on failure
 *
 * This function fills in the TLS record layer header, adds HMAC, and encrypts
 * the data using the current write cipher.
 */
int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
		      size_t buf_size, const u8 *payload, size_t payload_len,
		      size_t *out_len)
{
	u8 *pos, *ct_start, *length, *cpayload;
	struct crypto_hash *hmac;
	size_t clen;
	int explicit_iv;

	pos = buf;
	if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
		return -1;

	/* ContentType type */
	ct_start = pos;
	*pos++ = content_type;
	/* ProtocolVersion version */
	WPA_PUT_BE16(pos, rl->tls_version);
	pos += 2;
	/* uint16 length */
	length = pos;
	WPA_PUT_BE16(length, payload_len);
	pos += 2;

	cpayload = pos;
	explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
		rl->iv_size && rl->tls_version == TLS_VERSION_1_1;
	if (explicit_iv) {
		/* opaque IV[Cipherspec.block_length] */
		if (pos + rl->iv_size > buf + buf_size)
			return -1;

		/*
		 * Use random number R per the RFC 4346, 6.2.3.2 CBC Block
		 * Cipher option 2a.
		 */

		if (os_get_random(pos, rl->iv_size))
			return -1;
		pos += rl->iv_size;
	}

	/*
	 * opaque fragment[TLSPlaintext.length]
	 * (opaque content[TLSCompressed.length] in GenericBlockCipher)
	 */
	if (pos + payload_len > buf + buf_size)
		return -1;
	os_memmove(pos, payload, payload_len);
	pos += payload_len;

	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
		/*
		 * MAC calculated over seq_num + TLSCompressed.type +
		 * TLSCompressed.version + TLSCompressed.length +
		 * TLSCompressed.fragment
		 */
		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
					rl->hash_size);
		if (hmac == NULL) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
				   "to initialize HMAC");
			return -1;
		}
		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
		/* type + version + length + fragment */
		crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN);
		crypto_hash_update(hmac, payload, payload_len);
		clen = buf + buf_size - pos;
		if (clen < rl->hash_size) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
				   "enough room for MAC");
			crypto_hash_finish(hmac, NULL, NULL);
			return -1;
		}

		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
				   "to calculate HMAC");
			return -1;
		}
		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
			    pos, clen);
		pos += clen;
		if (rl->iv_size) {
			size_t len = pos - cpayload;
			size_t pad;
			pad = (len + 1) % rl->iv_size;
			if (pad)
				pad = rl->iv_size - pad;
			if (pos + pad + 1 > buf + buf_size) {
				wpa_printf(MSG_DEBUG, "TLSv1: No room for "
					   "block cipher padding");
				return -1;
			}
			os_memset(pos, pad, pad + 1);
			pos += pad + 1;
		}

		if (crypto_cipher_encrypt(rl->write_cbc, cpayload,
					  cpayload, pos - cpayload) < 0)
			return -1;
	}

	WPA_PUT_BE16(length, pos - length - 2);
	inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);

	*out_len = pos - buf;

	return 0;
}
Exemplo n.º 11
0
extern "C" JNIEXPORT jint JNICALL Java_com_att_aro_pcap_AROCryptoAdapter_cryptohashInitUpdateFinish(
	JNIEnv *env, jobject obj, jint dir, jint hash_alg, jbyteArray keyBlock, jint hash_size, jint recType, jint payloadLen, jbyteArray plain, jbyteArray seqNum)
{
	int ret = ARO_CRYPTO_ERROR;
	__try
	{
		int i_dir = (int)dir;
		int i_hash_alg = (int)hash_alg;
		enum CRYPTO::crypto_hash_alg e_alg = (enum CRYPTO::crypto_hash_alg)i_hash_alg;
		int i_hash_size = (int)hash_size;
		int i_recType = (int)recType;
		int i_payloadLen = (int)payloadLen;

		jbyte* keyBlockbuff = NULL;
		keyBlockbuff = env->GetByteArrayElements(keyBlock, NULL);
		jbyte* plainbuff = NULL;
		plainbuff = env->GetByteArrayElements(plain, NULL);
		jbyte* seqNumbuff = NULL;
		seqNumbuff = env->GetByteArrayElements(seqNum, NULL);

		switch (i_dir) {
			case 1: //UPLINK
				hmac = CRYPTO::crypto_hash_init(e_alg, (const BYTE*)keyBlockbuff, i_hash_size);
				break;
			case 2: //DOWNLINK
				hmac = CRYPTO::crypto_hash_init(e_alg, (const BYTE*)keyBlockbuff + i_hash_size, i_hash_size);
				break;
		}

		BYTE tlsTypeVersion[3] = {0x16, 0x03, 0x01};	
		tlsTypeVersion[0] = i_recType;

		BYTE _payloadLen[2];
		
		_payloadLen[1] = BYTE(i_payloadLen & 0xFF);
		_payloadLen[0] = BYTE(i_payloadLen >> 8);

		//HMAC: type + version + length + fragment(payload)
		
		crypto_hash_update(hmac, (const BYTE*)seqNumbuff, TLS_SEQ_NUM_LEN);
		crypto_hash_update(hmac, tlsTypeVersion, 3);
		crypto_hash_update(hmac, _payloadLen, 2);
		crypto_hash_update(hmac, (const BYTE*)plainbuff, i_payloadLen);
	
		BYTE hashResults[256];
		size_t hashLen = sizeof(hashResults);
		crypto_hash_finish(hmac, hashResults, &hashLen);
	
		if (hashLen != i_hash_size ||
			memcmp(hashResults, plainbuff + i_payloadLen, i_hash_size) != 0
		) {
			return ret;
		}

		env->ReleaseByteArrayElements(keyBlock, keyBlockbuff, 0);
		env->ReleaseByteArrayElements(plain, plainbuff, 0);
		env->ReleaseByteArrayElements(seqNum, seqNumbuff, 0);
		ret = 0;
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
    {
		ret = ARO_CRYPTO_ERROR;
    }

	return ret;
}
Exemplo n.º 12
0
static int tls_write_client_finished(struct tlsv1_client *conn,
				     u8 **msgpos, u8 *end)
{
	u8 *pos, *hs_start;
	size_t rlen, hlen;
	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];

	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");

	/* Encrypted Handshake Message: Finished */

	hlen = MD5_MAC_LEN;
	if (conn->verify.md5_client == NULL ||
	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		conn->verify.md5_client = NULL;
		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
		conn->verify.sha1_client = NULL;
		return -1;
	}
	conn->verify.md5_client = NULL;
	hlen = SHA1_MAC_LEN;
	if (conn->verify.sha1_client == NULL ||
	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
			       &hlen) < 0) {
		conn->verify.sha1_client = NULL;
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	conn->verify.sha1_client = NULL;

	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);

	/* Handshake */
	pos = hs_start = verify_data;
	/* HandshakeType msg_type */
	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
	/* uint24 length */
	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
	pos += 3;
	pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */
	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);

	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
			      &rlen) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}

	*msgpos += rlen;

	return 0;
}
Exemplo n.º 13
0
/**
 * tlsv1_record_receive - TLS record layer: Process a received message
 * @rl: Pointer to TLS record layer data
 * @in_data: Received data
 * @in_len: Length of the received data
 * @out_data: Buffer for output data (must be at least as long as in_data)
 * @out_len: Set to maximum out_data length by caller; used to return the
 * length of the used data
 * @alert: Buffer for returning an alert value on failure
 * Returns: 0 on success, -1 on failure
 *
 * This function decrypts the received message, verifies HMAC and TLS record
 * layer header.
 */
int tlsv1_record_receive(struct tlsv1_record_layer *rl,
			 const u8 *in_data, size_t in_len,
			 u8 *out_data, size_t *out_len, u8 *alert)
{
	size_t i, rlen, hlen;
	u8 padlen;
	struct crypto_hash *hmac;
	u8 len[2], hash[100];
	int force_mac_error = 0;

	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
		    in_data, in_len);

	if (in_len < TLS_RECORD_HEADER_LEN) {
		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
			   (unsigned long) in_len);
		*alert = TLS_ALERT_DECODE_ERROR;
		return -1;
	}

	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
		   "length %d", in_data[0], in_data[1], in_data[2],
		   WPA_GET_BE16(in_data + 3));

	if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
	    in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
	    in_data[0] != TLS_CONTENT_TYPE_ALERT &&
	    in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
			   in_data[0]);
		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
		return -1;
	}

	/*
	 * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
	 * protocol version in record layer. As such, accept any {03,xx} value
	 * to remain compatible with existing implementations.
	 */
	if (in_data[1] != 0x03) {
		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
			   "%u.%u", in_data[1], in_data[2]);
		*alert = TLS_ALERT_PROTOCOL_VERSION;
		return -1;
	}

	rlen = WPA_GET_BE16(in_data + 3);

	/* TLSCiphertext must not be more than 2^14+2048 bytes */
	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
			   (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
		*alert = TLS_ALERT_RECORD_OVERFLOW;
		return -1;
	}

	in_data += TLS_RECORD_HEADER_LEN;
	in_len -= TLS_RECORD_HEADER_LEN;

	if (rlen > in_len) {
		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
			   "(rlen=%lu > in_len=%lu)",
			   (unsigned long) rlen, (unsigned long) in_len);
		*alert = TLS_ALERT_DECODE_ERROR;
		return -1;
	}

	in_len = rlen;

	if (*out_len < in_len) {
		wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
			   "processing received record");
		*alert = TLS_ALERT_INTERNAL_ERROR;
		return -1;
	}

	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
		size_t plen;
		if (crypto_cipher_decrypt(rl->read_cbc, in_data,
					  out_data, in_len) < 0) {
			*alert = TLS_ALERT_DECRYPTION_FAILED;
			return -1;
		}
		plen = in_len;
		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
				"data", out_data, plen);

		if (rl->iv_size) {
			/*
			 * TLS v1.0 defines different alert values for various
			 * failures. That may information to aid in attacks, so
			 * use the same bad_record_mac alert regardless of the
			 * issues.
			 *
			 * In addition, instead of returning immediately on
			 * error, run through the MAC check to make timing
			 * attacks more difficult.
			 */

			if (rl->tls_version == TLS_VERSION_1_1) {
				/* Remove opaque IV[Cipherspec.block_length] */
				if (plen < rl->iv_size) {
					wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
						   "enough room for IV");
					force_mac_error = 1;
					goto check_mac;
				}
				os_memmove(out_data, out_data + rl->iv_size,
					   plen - rl->iv_size);
				plen -= rl->iv_size;
			}

			/* Verify and remove padding */
			if (plen == 0) {
				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
					   " (no pad)");
				force_mac_error = 1;
				goto check_mac;
			}
			padlen = out_data[plen - 1];
			if (padlen >= plen) {
				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
					   "length (%u, plen=%lu) in "
					   "received record",
					   padlen, (unsigned long) plen);
				force_mac_error = 1;
				goto check_mac;
			}
			for (i = plen - padlen; i < plen; i++) {
				if (out_data[i] != padlen) {
					wpa_hexdump(MSG_DEBUG,
						    "TLSv1: Invalid pad in "
						    "received record",
						    out_data + plen - padlen,
						    padlen);
					force_mac_error = 1;
					goto check_mac;
				}
			}

			plen -= padlen + 1;
		}

	check_mac:
		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
				"data with IV and padding removed",
				out_data, plen);

		if (plen < rl->hash_size) {
			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
				   "hash value");
			*alert = TLS_ALERT_BAD_RECORD_MAC;
			return -1;
		}

		plen -= rl->hash_size;

		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
					rl->hash_size);
		if (hmac == NULL) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
				   "to initialize HMAC");
			*alert = TLS_ALERT_INTERNAL_ERROR;
			return -1;
		}

		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
		/* type + version + length + fragment */
		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
		WPA_PUT_BE16(len, plen);
		crypto_hash_update(hmac, len, 2);
		crypto_hash_update(hmac, out_data, plen);
		hlen = sizeof(hash);
		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
				   "to calculate HMAC");
			*alert = TLS_ALERT_INTERNAL_ERROR;
			return -1;
		}
		if (hlen != rl->hash_size ||
		    os_memcmp(hash, out_data + plen, hlen) != 0 ||
		    force_mac_error) {
			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
				   "received message (force_mac_error=%d)",
				   force_mac_error);
			*alert = TLS_ALERT_BAD_RECORD_MAC;
			return -1;
		}

		*out_len = plen;
	} else {
		os_memcpy(out_data, in_data, in_len);
		*out_len = in_len;
	}

	/* TLSCompressed must not be more than 2^14+1024 bytes */
	if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
			   (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
		*alert = TLS_ALERT_RECORD_OVERFLOW;
		return -1;
	}

	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);

	return 0;
}
Exemplo n.º 14
0
static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
					       u8 **msgpos, u8 *end)
{
	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
	size_t rlen, hlen, clen;
	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;

	pos = *msgpos;

	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
	rhdr = pos;
	pos += TLS_RECORD_HEADER_LEN;

	/* Handshake */
	hs_start = pos;
	/* HandshakeType msg_type */
	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
	/* uint24 length (to be filled) */
	hs_length = pos;
	pos += 3;

	/*
	 * RFC 2246: 7.4.3 and 7.4.8:
	 * Signature signature
	 *
	 * RSA:
	 * digitally-signed struct {
	 *     opaque md5_hash[16];
	 *     opaque sha_hash[20];
	 * };
	 *
	 * DSA:
	 * digitally-signed struct {
	 *     opaque sha_hash[20];
	 * };
	 *
	 * The hash values are calculated over all handshake messages sent or
	 * received starting at ClientHello up to, but not including, this
	 * CertificateVerify message, including the type and length fields of
	 * the handshake messages.
	 */

	hpos = hash;

	if (alg == SIGN_ALG_RSA) {
		hlen = MD5_MAC_LEN;
		if (conn->verify.md5_cert == NULL ||
		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
		{
			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
				  TLS_ALERT_INTERNAL_ERROR);
			conn->verify.md5_cert = NULL;
			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
			conn->verify.sha1_cert = NULL;
			return -1;
		}
		hpos += MD5_MAC_LEN;
	} else
		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);

	conn->verify.md5_cert = NULL;
	hlen = SHA1_MAC_LEN;
	if (conn->verify.sha1_cert == NULL ||
	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
		conn->verify.sha1_cert = NULL;
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	conn->verify.sha1_cert = NULL;

	if (alg == SIGN_ALG_RSA)
		hlen += MD5_MAC_LEN;

	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);

	/*
	 * RFC 2246, 4.7:
	 * In digital signing, one-way hash functions are used as input for a
	 * signing algorithm. A digitally-signed element is encoded as an
	 * opaque vector <0..2^16-1>, where the length is specified by the
	 * signing algorithm and key.
	 *
	 * In RSA signing, a 36-byte structure of two hashes (one SHA and one
	 * MD5) is signed (encrypted with the private key). It is encoded with
	 * PKCS #1 block type 0 or type 1 as described in [PKCS1].
	 */
	signed_start = pos; /* length to be filled */
	pos += 2;
	clen = end - pos;
	if (conn->cred == NULL ||
	    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
					  pos, &clen) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	WPA_PUT_BE16(signed_start, clen);

	pos += clen;

	WPA_PUT_BE24(hs_length, pos - hs_length - 3);

	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	pos = rhdr + rlen;

	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);

	*msgpos = pos;

	return 0;
}
void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest)
{
	size_t len = SHA256_MAC_LEN;
	crypto_hash_finish(hash, digest, &len);
}
Exemplo n.º 16
0
static int tls_write_server_finished(struct tlsv1_server *conn,
				     u8 **msgpos, u8 *end)
{
	u8 *pos, *rhdr, *hs_start, *hs_length;
	size_t rlen, hlen;
	u8 verify_data[TLS_VERIFY_DATA_LEN];
	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];

	pos = *msgpos;

	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");

	/* Encrypted Handshake Message: Finished */

	hlen = MD5_MAC_LEN;
	if (conn->verify.md5_server == NULL ||
	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
				   TLS_ALERT_INTERNAL_ERROR);
		conn->verify.md5_server = NULL;
		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
		conn->verify.sha1_server = NULL;
		return -1;
	}
	conn->verify.md5_server = NULL;
	hlen = SHA1_MAC_LEN;
	if (conn->verify.sha1_server == NULL ||
	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
			       &hlen) < 0) {
		conn->verify.sha1_server = NULL;
		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
				   TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	conn->verify.sha1_server = NULL;

	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
		    verify_data, TLS_VERIFY_DATA_LEN)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
				   TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
			verify_data, TLS_VERIFY_DATA_LEN);

	rhdr = pos;
	pos += TLS_RECORD_HEADER_LEN;
	/* Handshake */
	hs_start = pos;
	/* HandshakeType msg_type */
	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
	/* uint24 length (to be filled) */
	hs_length = pos;
	pos += 3;
	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
	pos += TLS_VERIFY_DATA_LEN;
	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);

	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
				   TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}

	pos = rhdr + rlen;

	*msgpos = pos;

	return 0;
}
static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
					       u8 **msgpos, u8 *end)
{
	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
	size_t rlen, hlen, clen;
	u8 hash[100], *hpos;
	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;

	pos = *msgpos;

	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
	rhdr = pos;
	pos += TLS_RECORD_HEADER_LEN;

	/* Handshake */
	hs_start = pos;
	/* HandshakeType msg_type */
	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
	/* uint24 length (to be filled) */
	hs_length = pos;
	pos += 3;

	/*
	 * RFC 2246: 7.4.3 and 7.4.8:
	 * Signature signature
	 *
	 * RSA:
	 * digitally-signed struct {
	 *     opaque md5_hash[16];
	 *     opaque sha_hash[20];
	 * };
	 *
	 * DSA:
	 * digitally-signed struct {
	 *     opaque sha_hash[20];
	 * };
	 *
	 * The hash values are calculated over all handshake messages sent or
	 * received starting at ClientHello up to, but not including, this
	 * CertificateVerify message, including the type and length fields of
	 * the handshake messages.
	 */

	hpos = hash;

#ifdef CONFIG_TLSV12
	if (conn->rl.tls_version == TLS_VERSION_1_2) {
		hlen = SHA256_MAC_LEN;
		if (conn->verify.sha256_cert == NULL ||
		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
		    0) {
			conn->verify.sha256_cert = NULL;
			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
				  TLS_ALERT_INTERNAL_ERROR);
			return -1;
		}
		conn->verify.sha256_cert = NULL;

		/*
		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
		 *
		 * DigestInfo ::= SEQUENCE {
		 *   digestAlgorithm DigestAlgorithm,
		 *   digest OCTET STRING
		 * }
		 *
		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
		 *
		 * DER encoded DigestInfo for SHA256 per RFC 3447:
		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
		 * H
		 */
		os_memmove(hash + 19, hash, hlen);
		hlen += 19;
		os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
			  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
	} else {
#endif /* CONFIG_TLSV12 */

	if (alg == SIGN_ALG_RSA) {
		hlen = MD5_MAC_LEN;
		if (conn->verify.md5_cert == NULL ||
		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
		{
			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
				  TLS_ALERT_INTERNAL_ERROR);
			conn->verify.md5_cert = NULL;
			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
			conn->verify.sha1_cert = NULL;
			return -1;
		}
		hpos += MD5_MAC_LEN;
	} else
		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);

	conn->verify.md5_cert = NULL;
	hlen = SHA1_MAC_LEN;
	if (conn->verify.sha1_cert == NULL ||
	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
		conn->verify.sha1_cert = NULL;
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	conn->verify.sha1_cert = NULL;

	if (alg == SIGN_ALG_RSA)
		hlen += MD5_MAC_LEN;

#ifdef CONFIG_TLSV12
	}
#endif /* CONFIG_TLSV12 */

	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);

#ifdef CONFIG_TLSV12
	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
		/*
		 * RFC 5246, 4.7:
		 * TLS v1.2 adds explicit indication of the used signature and
		 * hash algorithms.
		 *
		 * struct {
		 *   HashAlgorithm hash;
		 *   SignatureAlgorithm signature;
		 * } SignatureAndHashAlgorithm;
		 */
		*pos++ = TLS_HASH_ALG_SHA256;
		*pos++ = TLS_SIGN_ALG_RSA;
	}
#endif /* CONFIG_TLSV12 */

	/*
	 * RFC 2246, 4.7:
	 * In digital signing, one-way hash functions are used as input for a
	 * signing algorithm. A digitally-signed element is encoded as an
	 * opaque vector <0..2^16-1>, where the length is specified by the
	 * signing algorithm and key.
	 *
	 * In RSA signing, a 36-byte structure of two hashes (one SHA and one
	 * MD5) is signed (encrypted with the private key). It is encoded with
	 * PKCS #1 block type 0 or type 1 as described in [PKCS1].
	 */
	signed_start = pos; /* length to be filled */
	pos += 2;
	clen = end - pos;
	if (conn->cred == NULL ||
	    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
					  pos, &clen) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	WPA_PUT_BE16(signed_start, clen);

	pos += clen;

	WPA_PUT_BE24(hs_length, pos - hs_length - 3);

	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
			      rhdr, end - rhdr, hs_start, pos - hs_start,
			      &rlen) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	pos = rhdr + rlen;

	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);

	*msgpos = pos;

	return 0;
}