blob: d3b4809c80005026bcbe32d3b5bb021b3a72a999 [file] [log] [blame]
/*
* Embedded Linux library
*
* Copyright (C) 2015 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include "util.h"
#include "private.h"
#include "tls.h"
#include "checksum.h"
#include "cipher.h"
#include "random.h"
#include "pem.h"
#include "tls-private.h"
#include "key.h"
#include "asn1-private.h"
void tls10_prf(const uint8_t *secret, size_t secret_len,
const char *label,
const uint8_t *seed, size_t seed_len,
uint8_t *out, size_t out_len)
{
uint8_t p_hash2[out_len];
uint8_t l_s1 = (secret_len + 1) / 2;
unsigned int i;
tls12_prf(L_CHECKSUM_MD5, 16,
secret, l_s1,
label, seed, seed_len,
out, out_len);
tls12_prf(L_CHECKSUM_SHA1, 20,
secret + secret_len - l_s1, l_s1,
label, seed, seed_len,
p_hash2, out_len);
for (i = 0; i < out_len; i++)
out[i] ^= p_hash2[i];
}
void tls12_prf(enum l_checksum_type type, size_t hash_len,
const uint8_t *secret, size_t secret_len,
const char *label,
const uint8_t *seed, size_t seed_len,
uint8_t *out, size_t out_len)
{
struct l_checksum *hmac = l_checksum_new_hmac(type, secret, secret_len);
size_t a_len, chunk_len, prfseed_len = strlen(label) + seed_len;
uint8_t a[128], prfseed[prfseed_len];
/* Generate the hash seed or A(0) as label + seed */
memcpy(prfseed, label, strlen(label));
memcpy(prfseed + strlen(label), seed, seed_len);
memcpy(a, prfseed, prfseed_len);
a_len = prfseed_len;
while (out_len) {
/* Generate A(i) */
l_checksum_reset(hmac);
l_checksum_update(hmac, a, a_len);
l_checksum_get_digest(hmac, a, hash_len);
a_len = hash_len;
/* Append seed & generate output */
memcpy(a + a_len, prfseed, prfseed_len);
l_checksum_reset(hmac);
l_checksum_update(hmac, a, a_len + prfseed_len);
chunk_len = out_len < hash_len ? out_len : hash_len;
l_checksum_get_digest(hmac, out, chunk_len);
out += chunk_len;
out_len -= chunk_len;
}
l_checksum_free(hmac);
}
void tls_prf_get_bytes(struct l_tls *tls,
enum l_checksum_type type, size_t hash_len,
const uint8_t *secret, size_t secret_len,
const char *label,
const uint8_t *seed, size_t seed_len,
uint8_t *buf, size_t len)
{
if (tls->negotiated_version >= TLS_V12)
tls12_prf(type, hash_len, secret, secret_len, label,
seed, seed_len, buf, len);
else
tls10_prf(secret, secret_len, label, seed, seed_len, buf, len);
}
static void tls_write_random(uint8_t *buf)
{
l_put_be32(time(NULL), buf);
l_getrandom(buf + 4, 28);
}
static void tls_drop_handshake_hash(struct l_tls *tls,
enum handshake_hash_type hash)
{
if (tls->handshake_hash[hash]) {
l_checksum_free(tls->handshake_hash[hash]);
tls->handshake_hash[hash] = NULL;
}
}
static void tls_reset_handshake(struct l_tls *tls)
{
enum handshake_hash_type hash;
memset(tls->pending.key_block, 0, sizeof(tls->pending.key_block));
l_free(tls->peer_cert);
l_key_free(tls->peer_pubkey);
tls->peer_cert = NULL;
tls->peer_pubkey = NULL;
tls->peer_pubkey_size = 0;
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
tls_drop_handshake_hash(tls, hash);
tls->state = TLS_HANDSHAKE_WAIT_HELLO;
tls->cert_requested = 0;
tls->cert_sent = 0;
}
static void tls_cleanup_handshake(struct l_tls *tls)
{
memset(tls->pending.client_random, 0, 32);
memset(tls->pending.server_random, 0, 32);
memset(tls->pending.master_secret, 0, 48);
}
static bool tls_change_cipher_spec(struct l_tls *tls, bool txrx)
{
struct tls_bulk_encryption_algorithm *enc;
struct tls_mac_algorithm *mac;
int key_offset;
if (tls->cipher[txrx]) {
l_cipher_free(tls->cipher[txrx]);
tls->cipher[txrx] = NULL;
tls->cipher_type[txrx] = TLS_CIPHER_STREAM;
}
if (tls->mac[txrx]) {
l_checksum_free(tls->mac[txrx]);
tls->mac[txrx] = NULL;
}
tls->mac_length[txrx] = 0;
tls->block_length[txrx] = 0;
tls->record_iv_length[txrx] = 0;
tls->seq_num[txrx] = 0;
tls->cipher_suite[txrx] = tls->pending.cipher_suite;
if (!tls->cipher_suite[txrx])
return true;
key_offset = 0;
if (tls->cipher_suite[txrx]->mac) {
mac = tls->cipher_suite[txrx]->mac;
/* Server write / client read is 2nd in the key block */
if ((tls->server && txrx) || (!tls->server && !txrx))
key_offset += mac->mac_length;
tls->mac[txrx] = l_checksum_new_hmac(mac->hmac_type,
tls->pending.key_block +
key_offset, mac->mac_length);
/* Wipe out the now unneeded part of the key block */
memset(tls->pending.key_block + key_offset, 0, mac->mac_length);
if (!tls->mac[txrx])
return false;
tls->mac_length[txrx] = mac->mac_length;
key_offset = 2 * mac->mac_length;
}
if (tls->cipher_suite[txrx]->encryption) {
enc = tls->cipher_suite[txrx]->encryption;
/* Server write / client read is 4th in the key block */
if ((tls->server && txrx) || (!tls->server && !txrx))
key_offset += enc->key_length;
tls->cipher[txrx] = l_cipher_new(enc->l_id,
tls->pending.key_block +
key_offset, enc->key_length);
/* Wipe out the now unneeded part of the key block */
memset(tls->pending.key_block + key_offset, 0, enc->key_length);
if (!tls->cipher[txrx])
return false;
tls->cipher_type[txrx] = enc->cipher_type;
if (enc->cipher_type == TLS_CIPHER_BLOCK) {
tls->record_iv_length[txrx] = enc->iv_length;
tls->block_length[txrx] = enc->block_length;
}
if ((tls->server && txrx) || (!tls->server && !txrx))
key_offset += enc->key_length;
else
key_offset += 2 * enc->key_length;
}
if (tls->negotiated_version <= TLS_V10 &&
tls->cipher_suite[txrx]->encryption &&
tls->cipher_suite[txrx]->encryption->cipher_type ==
TLS_CIPHER_BLOCK) {
enc = tls->cipher_suite[txrx]->encryption;
/* Server write / client read is 6th in the key block */
if ((tls->server && txrx) || (!tls->server && !txrx))
key_offset += enc->iv_length;
l_cipher_set_iv(tls->cipher[txrx], tls->pending.key_block +
key_offset, enc->iv_length);
/* Wipe out the now unneeded part of the key block */
memset(tls->pending.key_block + key_offset, 0, enc->iv_length);
}
return true;
}
static void tls_reset_cipher_spec(struct l_tls *tls, bool txrx)
{
/* Reset everything to the TLS_NULL_WITH_NULL_NULL state */
tls->pending.cipher_suite = NULL;
tls_change_cipher_spec(tls, txrx);
}
static bool tls_send_rsa_client_key_xchg(struct l_tls *tls);
static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
const uint8_t *buf, size_t len);
static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
tls_get_hash_t get_hash);
static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
tls_get_hash_t get_hash);
static bool tls_rsa_validate_cert_key(struct tls_cert *cert)
{
return tls_cert_get_pubkey_type(cert) == TLS_CERT_KEY_RSA;
}
static struct tls_key_exchange_algorithm tls_rsa = {
.id = 1, /* RSA_sign */
.certificate_check = true,
.validate_cert_key_type = tls_rsa_validate_cert_key,
.send_client_key_exchange = tls_send_rsa_client_key_xchg,
.handle_client_key_exchange = tls_handle_rsa_client_key_xchg,
.sign = tls_rsa_sign,
.verify = tls_rsa_verify,
};
static struct tls_bulk_encryption_algorithm tls_rc4 = {
.cipher_type = TLS_CIPHER_STREAM,
.l_id = L_CIPHER_ARC4,
.key_length = 16,
}, tls_aes128 = {
.cipher_type = TLS_CIPHER_BLOCK,
.l_id = L_CIPHER_AES_CBC,
.key_length = 16,
.iv_length = 16,
.block_length = 16,
}, tls_aes256 = {
.cipher_type = TLS_CIPHER_BLOCK,
.l_id = L_CIPHER_AES_CBC,
.key_length = 32,
.iv_length = 16,
.block_length = 16,
}, tls_3des_ede = {
.cipher_type = TLS_CIPHER_BLOCK,
.l_id = L_CIPHER_DES3_EDE_CBC,
.key_length = 24,
.iv_length = 8,
.block_length = 8,
};
static struct tls_mac_algorithm tls_md5 = {
.id = 1,
.hmac_type = L_CHECKSUM_MD5,
.mac_length = 16,
}, tls_sha = {
.id = 2,
.hmac_type = L_CHECKSUM_SHA1,
.mac_length = 20,
}, tls_sha256 = {
.id = 4,
.hmac_type = L_CHECKSUM_SHA256,
.mac_length = 32,
};
static struct tls_cipher_suite tls_cipher_suite_pref[] = {
{
.id = { 0x00, 0x35 },
.name = "TLS_RSA_WITH_AES_256_CBC_SHA",
.verify_data_length = 12,
.encryption = &tls_aes256,
.mac = &tls_sha,
.key_xchg = &tls_rsa,
},
{
.id = { 0x00, 0x2f },
.name = "TLS_RSA_WITH_AES_128_CBC_SHA",
.verify_data_length = 12,
.encryption = &tls_aes128,
.mac = &tls_sha,
.key_xchg = &tls_rsa,
},
{
.id = { 0x00, 0x3d },
.name = "TLS_RSA_WITH_AES_256_CBC_SHA256",
.verify_data_length = 12,
.encryption = &tls_aes256,
.mac = &tls_sha256,
.key_xchg = &tls_rsa,
},
{
.id = { 0x00, 0x3c },
.name = "TLS_RSA_WITH_AES_128_CBC_SHA256",
.verify_data_length = 12,
.encryption = &tls_aes128,
.mac = &tls_sha256,
.key_xchg = &tls_rsa,
},
{
.id = { 0x00, 0x0a },
.name = "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
.verify_data_length = 12,
.encryption = &tls_3des_ede,
.mac = &tls_sha,
.key_xchg = &tls_rsa,
},
{
.id = { 0x00, 0x05 },
.name = "TLS_RSA_WITH_RC4_128_SHA",
.verify_data_length = 12,
.encryption = &tls_rc4,
.mac = &tls_sha,
.key_xchg = &tls_rsa,
},
{
.id = { 0x00, 0x04 },
.name = "TLS_RSA_WITH_RC4_128_MD5",
.verify_data_length = 12,
.encryption = &tls_rc4,
.mac = &tls_md5,
.key_xchg = &tls_rsa,
},
};
static struct tls_cipher_suite *tls_find_cipher_suite(const uint8_t *id)
{
int i;
for (i = 0; i < (int) L_ARRAY_SIZE(tls_cipher_suite_pref); i++)
if (tls_cipher_suite_pref[i].id[0] == id[0] &&
tls_cipher_suite_pref[i].id[1] == id[1])
return &tls_cipher_suite_pref[i];
return NULL;
}
static struct tls_compression_method tls_compression_pref[] = {
/* CompressionMethod.null */
{
0,
},
};
static struct tls_compression_method *tls_find_compression_method(
const uint8_t id)
{
int i;
for (i = 0; i < (int) L_ARRAY_SIZE(tls_compression_pref); i++)
if (tls_compression_pref[i].id == id)
return &tls_compression_pref[i];
return NULL;
}
static const struct tls_hash_algorithm tls_handshake_hash_data[] = {
[HANDSHAKE_HASH_SHA256] = { 4, L_CHECKSUM_SHA256, 32 },
[HANDSHAKE_HASH_MD5] = { 1, L_CHECKSUM_MD5, 16 },
[HANDSHAKE_HASH_SHA1] = { 2, L_CHECKSUM_SHA1, 20 },
};
static bool tls_init_handshake_hash(struct l_tls *tls)
{
enum handshake_hash_type hash;
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) {
if (tls->handshake_hash[hash])
goto err;
tls->handshake_hash[hash] = l_checksum_new(
tls_handshake_hash_data[hash].l_id);
if (!tls->handshake_hash[hash])
goto err;
}
return true;
err:
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
tls_drop_handshake_hash(tls, hash);
return false;
}
enum tls_handshake_type {
TLS_HELLO_REQUEST = 0,
TLS_CLIENT_HELLO = 1,
TLS_SERVER_HELLO = 2,
TLS_CERTIFICATE = 11,
TLS_SERVER_KEY_EXCHANGE = 12,
TLS_CERTIFICATE_REQUEST = 13,
TLS_SERVER_HELLO_DONE = 14,
TLS_CERTIFICATE_VERIFY = 15,
TLS_CLIENT_KEY_EXCHANGE = 16,
TLS_FINISHED = 20,
};
static const uint8_t pkcs1_digest_info_md5_start[] = {
0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x02, 0x05, 0x05, 0x00, 0x04, 0x10,
};
static const uint8_t pkcs1_digest_info_sha1_start[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
0x00, 0x04, 0x14,
};
static const uint8_t pkcs1_digest_info_sha256_start[] = {
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
};
static const uint8_t pkcs1_digest_info_sha384_start[] = {
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30,
};
static const uint8_t pkcs1_digest_info_sha512_start[] = {
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40,
};
static void pkcs1_write_digest_info(enum l_checksum_type type,
uint8_t *out, size_t *out_len,
const uint8_t *hash, size_t hash_len)
{
switch (type) {
case L_CHECKSUM_MD5:
memcpy(out, pkcs1_digest_info_md5_start,
sizeof(pkcs1_digest_info_md5_start));
*out_len = sizeof(pkcs1_digest_info_md5_start);
break;
case L_CHECKSUM_SHA1:
memcpy(out, pkcs1_digest_info_sha1_start,
sizeof(pkcs1_digest_info_sha1_start));
*out_len = sizeof(pkcs1_digest_info_sha1_start);
break;
case L_CHECKSUM_SHA256:
memcpy(out, pkcs1_digest_info_sha256_start,
sizeof(pkcs1_digest_info_sha256_start));
*out_len = sizeof(pkcs1_digest_info_sha256_start);
break;
case L_CHECKSUM_SHA384:
memcpy(out, pkcs1_digest_info_sha384_start,
sizeof(pkcs1_digest_info_sha384_start));
*out_len = sizeof(pkcs1_digest_info_sha384_start);
break;
case L_CHECKSUM_SHA512:
memcpy(out, pkcs1_digest_info_sha512_start,
sizeof(pkcs1_digest_info_sha512_start));
*out_len = sizeof(pkcs1_digest_info_sha512_start);
break;
default:
abort();
}
memcpy(out + *out_len, hash, hash_len);
*out_len += hash_len;
}
static void tls_send_alert(struct l_tls *tls, bool fatal,
enum l_tls_alert_desc alert_desc)
{
uint8_t buf[2];
buf[0] = fatal ? 2 : 1;
buf[1] = alert_desc;
tls_tx_record(tls, TLS_CT_ALERT, buf, 2);
}
/*
* Callers make sure this is about the last function before returning
* from the stack frames up to the exported library call so that the
* user-supplied disconnected callback here is free to use l_tls_free
* for example.
*/
void tls_disconnect(struct l_tls *tls, enum l_tls_alert_desc desc,
enum l_tls_alert_desc local_desc)
{
tls_send_alert(tls, true, desc);
tls_reset_handshake(tls);
tls_cleanup_handshake(tls);
tls_reset_cipher_spec(tls, 0);
tls_reset_cipher_spec(tls, 1);
tls->negotiated_version = 0;
tls->ready = false;
tls->disconnected(local_desc ?: desc, local_desc && !desc,
tls->user_data);
}
#define TLS_HANDSHAKE_HEADER_SIZE 4
static void tls_tx_handshake(struct l_tls *tls, int type, uint8_t *buf,
size_t length)
{
int i;
/* Fill in the handshake header */
buf[0] = type;
buf[1] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 16;
buf[2] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 8;
buf[3] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 0;
for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
if (tls->handshake_hash[i])
l_checksum_update(tls->handshake_hash[i], buf, length);
tls_tx_record(tls, TLS_CT_HANDSHAKE, buf, length);
}
static void tls_send_client_hello(struct l_tls *tls)
{
uint8_t buf[128 + L_ARRAY_SIZE(tls_compression_pref) +
2 * L_ARRAY_SIZE(tls_cipher_suite_pref)];
uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
int i;
/* Fill in the Client Hello body */
*ptr++ = (uint8_t) (TLS_VERSION >> 8);
*ptr++ = (uint8_t) (TLS_VERSION >> 0);
tls_write_random(tls->pending.client_random);
memcpy(ptr, tls->pending.client_random, 32);
ptr += 32;
*ptr++ = 0; /* No SessionID */
/*
* We can list all supported key exchange mechanisms regardless of the
* certificate type we are actually presenting (if any).
*
* TODO: perhaps scan /proc/crypto for supported ciphers so we don't
* include ones that will cause an internal error later in the
* handshake. We can add camellia whan this is done.
*/
l_put_be16(L_ARRAY_SIZE(tls_cipher_suite_pref) * 2, ptr);
ptr += 2;
for (i = 0; i < (int) L_ARRAY_SIZE(tls_cipher_suite_pref); i++) {
*ptr++ = tls_cipher_suite_pref[i].id[0];
*ptr++ = tls_cipher_suite_pref[i].id[1];
}
*ptr++ = L_ARRAY_SIZE(tls_compression_pref);
for (i = 0; i < (int) L_ARRAY_SIZE(tls_compression_pref); i++)
*ptr++ = tls_compression_pref[i].id;
tls_tx_handshake(tls, TLS_CLIENT_HELLO, buf, ptr - buf);
}
static void tls_send_server_hello(struct l_tls *tls)
{
uint8_t buf[128];
uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
/* Fill in the Server Hello body */
*ptr++ = tls->negotiated_version >> 8;
*ptr++ = tls->negotiated_version >> 0;
tls_write_random(tls->pending.server_random);
memcpy(ptr, tls->pending.server_random, 32);
ptr += 32;
*ptr++ = 0; /* Sessions are not cached */
*ptr++ = tls->pending.cipher_suite->id[0];
*ptr++ = tls->pending.cipher_suite->id[1];
*ptr++ = tls->pending.compression_method->id;
tls_tx_handshake(tls, TLS_SERVER_HELLO, buf, ptr - buf);
}
static bool tls_send_certificate(struct l_tls *tls)
{
uint8_t *buf, *ptr;
struct tls_cert *cert, *i;
size_t total;
if (tls->cert_path)
cert = tls_cert_load_file(tls->cert_path);
else
cert = NULL;
if (tls->server && !cert) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
return false;
}
if (cert && !tls_cert_find_certchain(cert, tls->ca_cert_path)) {
if (tls->server) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_UNKNOWN_CA);
return false;
} else
cert = NULL;
}
/* TODO: might want check this earlier and exclude the cipher suite */
if (cert && !tls->pending.cipher_suite->key_xchg->
validate_cert_key_type(cert)) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_CERT_UNKNOWN);
return false;
}
/*
* TODO: check that the certificate is compatible with hash and
* signature algorithms lists supplied to us in the Client Hello
* extensions (if we're a server) or in the Certificate Request
* (if we act as a 1.2+ client).
*
* - for the hash and signature_algorithms list, check all
* certs in the cert chain.
*
* - also if !cipher_suite->key_xchg->key_exchange_msg, check that the
* end entity certificate's key type matches and is usable with some
* hash/signature pair.
*
* - on client check if any of the supplied DNs (if any) match
* anything in our cert chain.
*/
total = 0;
for (i = cert; i; i = i->issuer)
total += 3 + i->size;
buf = l_malloc(128 + total);
ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
/* Fill in the Certificate body */
*ptr++ = total >> 16;
*ptr++ = total >> 8;
*ptr++ = total >> 0;
for (i = cert; i; i = i->issuer) {
*ptr++ = i->size >> 16;
*ptr++ = i->size >> 8;
*ptr++ = i->size >> 0;
memcpy(ptr, i->asn1, i->size);
ptr += i->size;
}
tls_tx_handshake(tls, TLS_CERTIFICATE, buf, ptr - buf);
l_free(buf);
if (cert)
tls->cert_sent = true;
l_free(cert);
return true;
}
static uint8_t tls_cert_type_pref[] = {
1, /* RSA_sign */
};
struct tls_signature_hash_algorithms {
uint8_t hash_id;
uint8_t signature_id;
};
static struct tls_signature_hash_algorithms tls_signature_hash_pref[] = {
{ 6, 1 }, /* SHA512 + RSA */
{ 5, 1 }, /* SHA384 + RSA */
{ 4, 1 }, /* SHA256 + RSA */
{ 2, 1 }, /* SHA1 + RSA */
{ 1, 1 }, /* MD5 + RSA */
};
static bool tls_send_certificate_request(struct l_tls *tls)
{
uint8_t *buf, *ptr, *dn_ptr, *signature_hash_ptr;
unsigned int i;
buf = l_malloc(128 + L_ARRAY_SIZE(tls_cert_type_pref) +
2 * L_ARRAY_SIZE(tls_signature_hash_pref));
ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
/* Fill in the Certificate Request body */
*ptr++ = L_ARRAY_SIZE(tls_cert_type_pref);
for (i = 0; i < L_ARRAY_SIZE(tls_cert_type_pref); i++)
*ptr++ = tls_cert_type_pref[i];
/*
* This only makes sense as a variable-length field, assume there's
* a typo in RFC5246 7.4.4 here.
*
* TODO: we support the full list of hash algorithms when used
* in the client certificate chain but we can only verify the
* Certificate Verify signature when the hash algorithm matches
* one of HANDSHAKE_HASH_*. The values we include here will
* affect both of these steps so revisit which set we're passing
* here.
*/
if (tls->negotiated_version >= TLS_V12) {
signature_hash_ptr = ptr;
ptr += 2;
for (i = 0; i < L_ARRAY_SIZE(tls_signature_hash_pref); i++) {
*ptr++ = tls_signature_hash_pref[i].hash_id;
*ptr++ = tls_signature_hash_pref[i].signature_id;
}
l_put_be16(ptr - (signature_hash_ptr + 2), signature_hash_ptr);
}
dn_ptr = ptr;
ptr += 2; /* Leave space for sizes */
l_put_be16(0, dn_ptr); /* DistinguishedNames size */
tls_tx_handshake(tls, TLS_CERTIFICATE_REQUEST, buf, ptr - buf);
l_free(buf);
return true;
}
static void tls_send_server_hello_done(struct l_tls *tls)
{
uint8_t buf[32];
/* No body */
tls_tx_handshake(tls, TLS_SERVER_HELLO_DONE, buf,
TLS_HANDSHAKE_HEADER_SIZE);
}
static void tls_generate_master_secret(struct l_tls *tls,
const uint8_t *pre_master_secret,
int pre_master_secret_len)
{
uint8_t seed[64];
int key_block_size;
memcpy(seed + 0, tls->pending.client_random, 32);
memcpy(seed + 32, tls->pending.server_random, 32);
tls_prf_get_bytes(tls, L_CHECKSUM_SHA256, 32,
pre_master_secret, pre_master_secret_len,
"master secret", seed, 64,
tls->pending.master_secret, 48);
/* Directly generate the key block while we're at it */
key_block_size = 0;
if (tls->pending.cipher_suite->encryption)
key_block_size += 2 *
tls->pending.cipher_suite->encryption->key_length;
if (tls->pending.cipher_suite->mac)
key_block_size += 2 *
tls->pending.cipher_suite->mac->mac_length;
if (tls->pending.cipher_suite->encryption &&
tls->negotiated_version <= TLS_V10 &&
tls->pending.cipher_suite->encryption->cipher_type ==
TLS_CIPHER_BLOCK)
key_block_size += 2 *
tls->pending.cipher_suite->encryption->iv_length;
/* Note: 2x fixed_IV_length also needed for AEAD ciphers */
/* Reverse order from the master secret seed */
memcpy(seed + 0, tls->pending.server_random, 32);
memcpy(seed + 32, tls->pending.client_random, 32);
tls_prf_get_bytes(tls, L_CHECKSUM_SHA256, 32,
tls->pending.master_secret, 48,
"key expansion", seed, 64,
tls->pending.key_block, key_block_size);
memset(seed, 0, 64);
}
static bool tls_send_rsa_client_key_xchg(struct l_tls *tls)
{
uint8_t buf[1024 + 32];
uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
uint8_t pre_master_secret[48];
ssize_t bytes_encrypted;
if (!tls->peer_pubkey) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
return false;
}
pre_master_secret[0] = (uint8_t) (TLS_VERSION >> 8);
pre_master_secret[1] = (uint8_t) (TLS_VERSION >> 0);
l_getrandom(pre_master_secret + 2, 46);
if (tls->peer_pubkey_size + 32 > (int) sizeof(buf)) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
return false;
}
l_put_be16(tls->peer_pubkey_size, ptr);
bytes_encrypted = l_key_encrypt(tls->peer_pubkey,
L_KEY_RSA_PKCS1_V1_5, L_CHECKSUM_NONE,
pre_master_secret, ptr + 2, 48,
tls->peer_pubkey_size);
ptr += tls->peer_pubkey_size + 2;
if (bytes_encrypted != (ssize_t) tls->peer_pubkey_size) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
return false;
}
tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf);
tls_generate_master_secret(tls, pre_master_secret, 48);
memset(pre_master_secret, 0, 48);
return true;
}
static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
tls_get_hash_t get_hash)
{
ssize_t result;
const struct tls_hash_algorithm *hash_type;
uint8_t hash[HANDSHAKE_HASH_MAX_SIZE];
uint8_t sign_input[HANDSHAKE_HASH_MAX_SIZE * 2 + 32];
size_t sign_input_len;
bool prepend_hash_type = false;
size_t expected_bytes;
if (!tls->priv_key || !tls->priv_key_size) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
return -ENOKEY;
}
expected_bytes = tls->priv_key_size + 2;
if (tls->negotiated_version >= TLS_V12) {
hash_type = &tls_handshake_hash_data[tls->signature_hash];
get_hash(tls, hash_type->tls_id, hash, NULL, NULL);
pkcs1_write_digest_info(hash_type->l_id,
sign_input, &sign_input_len,
hash, hash_type->length);
prepend_hash_type = true;
expected_bytes += 2;
} else {
get_hash(tls, 1, sign_input + 0, NULL, NULL); /* MD5 */
get_hash(tls, 2, sign_input + 16, NULL, NULL); /* SHA1 */
sign_input_len = 36;
}
result = -EMSGSIZE;
if (len >= expected_bytes) {
if (prepend_hash_type) {
*out++ = hash_type->tls_id;
*out++ = 1; /* RSA_sign */
}
l_put_be16(tls->priv_key_size, out);
result = l_key_sign(tls->priv_key, L_KEY_RSA_PKCS1_V1_5,
L_CHECKSUM_NONE, sign_input, out + 2,
sign_input_len, tls->priv_key_size);
if (result == (ssize_t) tls->priv_key_size)
result = expected_bytes;
}
if (result < 0)
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
return result;
}
static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
tls_get_hash_t get_hash)
{
uint8_t hash[HANDSHAKE_HASH_MAX_SIZE];
size_t hash_len;
enum l_checksum_type hash_type;
uint8_t expected[HANDSHAKE_HASH_MAX_SIZE * 2 + 32];
size_t expected_len;
unsigned int offset;
bool success;
/* 2 bytes for SignatureAndHashAlgorithm if version >= 1.2 */
offset = 2;
if (tls->negotiated_version < TLS_V12)
offset = 0;
if (len < offset + 2 ||
(size_t) l_get_be16(in + offset) + offset + 2 != len) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
return false;
}
/* Only the default hash type supported */
if (len != offset + 2 + tls->peer_pubkey_size) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
return false;
}
if (tls->negotiated_version >= TLS_V12) {
/* Only RSA supported */
if (in[1] != 1 /* RSA_sign */) {
tls_disconnect(tls, TLS_ALERT_DECRYPT_ERROR, 0);
return false;
}
if (!get_hash(tls, in[0], hash, &hash_len, &hash_type)) {
tls_disconnect(tls, TLS_ALERT_DECRYPT_ERROR, 0);
return false;
}
/*
* TODO: According to 4.7 we need to support at least two forms
* of the signed content in the verification:
* - DigestInfo with NULL AlgorithmIdentifier.parameters,
* - DigestInfo with empty AlgorithmIdentifier.parameters.
*
* Additionally PKCS#1 now says BER is used in place of DER for
* DigestInfo encoding which adds more ambiguity in the
* encoding.
*/
pkcs1_write_digest_info(hash_type, expected, &expected_len,
hash, hash_len);
} else {
get_hash(tls, 1, expected + 0, NULL, NULL); /* MD5 */
get_hash(tls, 2, expected + 16, NULL, NULL); /* SHA1 */
expected_len = 36;
/*
* Within the RSA padding for signatures PKCS#1 1.5 allows
* the block format to be either 0 or 1, while PKCS#1 2.0
* mandates block type 1 making the signatures unambiguous.
* The l_asymmetric_cipher_verify implementation only
* accepts block type 1.
* TODO: TLS 1.0 doesn't specify that block type must be 1
* like TLS 1.2 does meaning that both PKCS#1 1.5 types are
* probably allowed.
*/
}
success = l_key_verify(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5,
L_CHECKSUM_NONE, expected, in + 4,
expected_len, tls->peer_pubkey_size);
if (!success)
tls_disconnect(tls, TLS_ALERT_DECRYPT_ERROR, 0);
return success;
}
static void tls_get_handshake_hash(struct l_tls *tls,
enum handshake_hash_type type,
uint8_t *out)
{
struct l_checksum *hash = l_checksum_clone(tls->handshake_hash[type]);
if (!hash)
return;
l_checksum_get_digest(hash, out, tls_handshake_hash_data[type].length);
l_checksum_free(hash);
}
static bool tls_get_handshake_hash_by_id(struct l_tls *tls, uint8_t hash_id,
uint8_t *out, size_t *len,
enum l_checksum_type *type)
{
enum handshake_hash_type hash;
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
if (tls_handshake_hash_data[hash].tls_id == hash_id &&
tls->handshake_hash[hash]) {
tls_get_handshake_hash(tls, hash, out);
if (len)
*len = tls_handshake_hash_data[hash].length;
if (type)
*type = tls_handshake_hash_data[hash].l_id;
return true;
}
return false;
}
static bool tls_send_certificate_verify(struct l_tls *tls)
{
uint8_t buf[2048];
int i;
ssize_t sign_len;
/* Fill in the Certificate Verify body */
sign_len = tls->pending.cipher_suite->key_xchg->sign(tls,
buf + TLS_HANDSHAKE_HEADER_SIZE,
2048 - TLS_HANDSHAKE_HEADER_SIZE,
tls_get_handshake_hash_by_id);
if (sign_len < 0)
return false;
/* Stop maintaining handshake message hashes other than SHA256. */
if (tls->negotiated_version >= TLS_V12)
for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
if (i != HANDSHAKE_HASH_SHA256)
tls_drop_handshake_hash(tls, i);
tls_tx_handshake(tls, TLS_CERTIFICATE_VERIFY, buf,
sign_len + TLS_HANDSHAKE_HEADER_SIZE);
return true;
}
static void tls_send_change_cipher_spec(struct l_tls *tls)
{
uint8_t buf = 1;
tls_tx_record(tls, TLS_CT_CHANGE_CIPHER_SPEC, &buf, 1);
}
static void tls_send_finished(struct l_tls *tls)
{
uint8_t buf[512];
uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
uint8_t seed[HANDSHAKE_HASH_MAX_SIZE * 2];
size_t seed_len;
if (tls->negotiated_version >= TLS_V12) {
/*
* Same hash type as that used for the PRF, i.e. SHA256
* unless an exotic cipher suite was negotiated that
* dictates a different hash for the PRF and for the
* Finished hash. We don't support any such ciphers so
* it's always SHA256.
*/
tls_get_handshake_hash(tls, HANDSHAKE_HASH_TLS12, seed);
seed_len = tls_handshake_hash_data[HANDSHAKE_HASH_TLS12].length;
} else {
tls_get_handshake_hash(tls, HANDSHAKE_HASH_MD5, seed + 0);
tls_get_handshake_hash(tls, HANDSHAKE_HASH_SHA1, seed + 16);
seed_len = 36;
}
tls_prf_get_bytes(tls, L_CHECKSUM_SHA256, 32,
tls->pending.master_secret, 48,
tls->server ? "server finished" :
"client finished",
seed, seed_len,
ptr, tls->cipher_suite[1]->verify_data_length);
ptr += tls->cipher_suite[1]->verify_data_length;
tls_tx_handshake(tls, TLS_FINISHED, buf, ptr - buf);
}
static bool tls_verify_finished(struct l_tls *tls, const uint8_t *received,
size_t len)
{
uint8_t expected[tls->cipher_suite[0]->verify_data_length];
uint8_t *seed;
size_t seed_len;
if (len != (size_t) tls->cipher_suite[0]->verify_data_length) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
return false;
}
if (tls->negotiated_version >= TLS_V12) {
seed = tls->prev_digest[HANDSHAKE_HASH_TLS12];
seed_len = tls_handshake_hash_data[HANDSHAKE_HASH_TLS12].length;
} else {
seed = alloca(36);
memcpy(seed + 0, tls->prev_digest[HANDSHAKE_HASH_MD5], 16);
memcpy(seed + 16, tls->prev_digest[HANDSHAKE_HASH_SHA1], 20);
seed_len = 36;
}
tls_prf_get_bytes(tls, L_CHECKSUM_SHA256, 32,
tls->pending.master_secret, 48,
tls->server ? "client finished" :
"server finished",
seed, seed_len,
expected,
tls->cipher_suite[0]->verify_data_length);
if (memcmp(received, expected, len)) {
tls_disconnect(tls, TLS_ALERT_DECRYPT_ERROR, 0);
return false;
}
return true;
}
static void tls_handle_client_hello(struct l_tls *tls,
const uint8_t *buf, size_t len)
{
uint16_t cipher_suites_size;
uint8_t session_id_size, compression_methods_size;
const uint8_t *cipher_suites;
const uint8_t *compression_methods;
int i;
/* Do we have enough for ProtocolVersion + Random + SessionID size? */
if (len < 2 + 32 + 1)
goto decode_error;
memcpy(tls->pending.client_random, buf + 2, 32);
session_id_size = buf[34];
len -= 35;
/*
* Do we have enough to hold the actual session ID + 2 byte field for
* cipher_suite len + minimum of a single cipher suite identifier
*/
if (len < (size_t) session_id_size + 4)
goto decode_error;
len -= session_id_size + 2;
cipher_suites_size = l_get_be16(buf + 35 + session_id_size);
cipher_suites = buf + 37 + session_id_size;
/*
* Check that size is not odd, more than 0 and we have enough
* data in the packet for cipher_suites_size + 2 bytes for
* compression_methods_size + a single compression method
*/
if (len < (size_t) cipher_suites_size + 2 ||
(cipher_suites_size & 1) || cipher_suites_size == 0)
goto decode_error;
len -= cipher_suites_size + 1;
compression_methods_size = cipher_suites[cipher_suites_size];
compression_methods = cipher_suites + cipher_suites_size + 1;
if (len < (size_t) compression_methods_size ||
compression_methods_size == 0)
goto decode_error;
len -= compression_methods_size;
if (len) {
uint16_t extensions_size;
if (len < 2 || len > 2 + 65535)
goto decode_error;
extensions_size = l_get_be16(compression_methods +
compression_methods_size);
len -= 2;
if (len != extensions_size)
goto decode_error;
/* TODO: validate each extension in the vector, 7.4.1.4 */
/* TODO: check for duplicates? */
}
/*
* Note: if the client is supplying a SessionID we know it is false
* because our server implementation never generates any SessionIDs
* yet so either the client is attempting something strange or was
* trying to connect somewhere else. We might want to throw an error.
*/
/*
* TODO: Obligatory in 1.2: check for signature_algorithms extension,
* store the list of algorithms for later checking in
* tls_send_certificate on both server and client sides. If not
* present assume only SHA1+RSA (7.4.1.4.1).
*/
/* Save client_version for Premaster Secret verification */
tls->client_version = l_get_be16(buf);
if (tls->client_version < TLS_MIN_VERSION) {
tls_disconnect(tls, TLS_ALERT_PROTOCOL_VERSION, 0);
return;
}
tls->negotiated_version = TLS_VERSION < tls->client_version ?
TLS_VERSION : tls->client_version;
/* Stop maintaining handshake message hashes other than MD1 and SHA. */
if (tls->negotiated_version < TLS_V12)
for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
tls_drop_handshake_hash(tls, i);
/* Select a cipher suite according to client's preference list */
while (cipher_suites_size) {
/*
* TODO: filter supported cipher suites by the certificate/key
* type that was submitted by tls_set_auth_data() if any.
* Perhaps just call cipher_suite->verify_cert_type() on each
* cipher suite passing a pre-parsed certificate ASN.1 struct.
*/
tls->pending.cipher_suite =
tls_find_cipher_suite(cipher_suites);
if (tls->pending.cipher_suite)
break;
cipher_suites += 2;
cipher_suites_size -= 2;
}
if (!cipher_suites_size) {
tls_disconnect(tls, TLS_ALERT_HANDSHAKE_FAIL, 0);
return;
}
/* Select a compression method */
/* CompressionMethod.null must be present in the vector */
if (!memchr(compression_methods, 0, compression_methods_size))
goto decode_error;
while (compression_methods_size) {
tls->pending.compression_method =
tls_find_compression_method(*compression_methods);
if (tls->pending.compression_method)
break;
compression_methods++;
compression_methods_size--;
}
tls_send_server_hello(tls);
if (tls->pending.cipher_suite->key_xchg->certificate_check &&
tls->cert_path)
if (!tls_send_certificate(tls))
return;
/* TODO: don't bother if configured to not authenticate client */
if (tls->pending.cipher_suite->key_xchg->certificate_check &&
tls->ca_cert_path)
if (!tls_send_certificate_request(tls))
return;
tls_send_server_hello_done(tls);
if (tls->pending.cipher_suite->key_xchg->certificate_check &&
tls->ca_cert_path)
tls->state = TLS_HANDSHAKE_WAIT_CERTIFICATE;
else
tls->state = TLS_HANDSHAKE_WAIT_KEY_EXCHANGE;
return;
decode_error:
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
}
static void tls_handle_server_hello(struct l_tls *tls,
const uint8_t *buf, size_t len)
{
uint8_t session_id_size, cipher_suite_id[2], compression_method_id;
int i;
/* Do we have enough for ProtocolVersion + Random + SessionID len ? */
if (len < 2 + 32 + 1)
goto decode_error;
memcpy(tls->pending.server_random, buf + 2, 32);
session_id_size = buf[34];
len -= 35;
/* Do we have enough for SessionID + CipherSuite ID + Compression ID */
if (len < (size_t) session_id_size + 2 + 1)
goto decode_error;
cipher_suite_id[0] = buf[35 + session_id_size + 0];
cipher_suite_id[1] = buf[35 + session_id_size + 1];
compression_method_id = buf[35 + session_id_size + 2];
len -= session_id_size + 2 + 1;
if (len != 0) { /* We know we haven't solicited any extensions */
tls_disconnect(tls, TLS_ALERT_UNSUPPORTED_EXTENSION, 0);
return;
}
tls->negotiated_version = l_get_be16(buf);
if (tls->negotiated_version < TLS_MIN_VERSION ||
tls->negotiated_version > TLS_VERSION) {
tls_disconnect(tls, tls->negotiated_version < TLS_MIN_VERSION ?
TLS_ALERT_PROTOCOL_VERSION :
TLS_ALERT_ILLEGAL_PARAM, 0);
return;
}
/* Stop maintaining handshake message hashes other than MD1 and SHA. */
if (tls->negotiated_version < TLS_V12)
for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
tls_drop_handshake_hash(tls, i);
/* Set the new cipher suite and compression method structs */
tls->pending.cipher_suite = tls_find_cipher_suite(cipher_suite_id);
if (!tls->pending.cipher_suite) {
tls_disconnect(tls, TLS_ALERT_HANDSHAKE_FAIL, 0);
return;
}
tls->pending.compression_method =
tls_find_compression_method(compression_method_id);
if (!tls->pending.compression_method) {
tls_disconnect(tls, TLS_ALERT_HANDSHAKE_FAIL, 0);
return;
}
if (tls->pending.cipher_suite->key_xchg->certificate_check)
tls->state = TLS_HANDSHAKE_WAIT_CERTIFICATE;
else
tls->state = TLS_HANDSHAKE_WAIT_KEY_EXCHANGE;
return;
decode_error:
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
}
static void tls_handle_certificate(struct l_tls *tls,
const uint8_t *buf, size_t len)
{
int total, cert_len;
struct tls_cert *certchain = NULL, **tail = &certchain;
struct tls_cert *ca_cert = NULL;
bool dummy;
/* Length checks */
total = *buf++ << 16;
total |= *buf++ << 8;
total |= *buf++ << 0;
if ((size_t) total + 3 != len)
goto decode_error;
while (total) {
cert_len = *buf++ << 16;
cert_len |= *buf++ << 8;
cert_len |= *buf++ << 0;
if (cert_len + 3 > total)
goto decode_error;
*tail = l_malloc(sizeof(struct tls_cert) + cert_len);
(*tail)->size = cert_len;
(*tail)->issuer = NULL;
memcpy((*tail)->asn1, buf, cert_len);
tail = &(*tail)->issuer;
buf += cert_len;
total -= cert_len + 3;
}
/*
* "Note that a client MAY send no certificates if it does not have any
* appropriate certificate to send in response to the server's
* authentication request." -- for now we unconditionally accept
* an empty certificate chain from the client. Later on we need to
* make this configurable, if we don't want to authenticate the
* client then also don't bother sending a Certificate Request.
*/
if (!certchain) {
if (!tls->server) {
tls_disconnect(tls, TLS_ALERT_HANDSHAKE_FAIL, 0);
goto done;
}
tls->state = TLS_HANDSHAKE_WAIT_KEY_EXCHANGE;
goto done;
}
/*
* Validate the certificate chain's consistency and validate it
* against our CA if we have any.
*/
if (tls->ca_cert_path) {
ca_cert = tls_cert_load_file(tls->ca_cert_path);
if (!ca_cert) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
goto done;
}
}
if (!tls_cert_verify_certchain(certchain, ca_cert)) {
tls_disconnect(tls, TLS_ALERT_BAD_CERT, 0);
goto done;
}
/*
* RFC5246 7.4.2:
* "The end entity certificate's public key (and associated
* restrictions) MUST be compatible with the selected key exchange
* algorithm."
*/
if (!tls->pending.cipher_suite->key_xchg->
validate_cert_key_type(certchain)) {
tls_disconnect(tls, TLS_ALERT_UNSUPPORTED_CERT, 0);
goto done;
}
/* Save the end-entity cert and free the rest of the chain */
tls->peer_cert = certchain;
tls_cert_free_certchain(certchain->issuer);
certchain->issuer = NULL;
certchain = NULL;
tls->peer_pubkey = l_key_new(L_KEY_RSA, tls->peer_cert->asn1,
tls->peer_cert->size);
if (!tls->peer_pubkey) {
tls_disconnect(tls, TLS_ALERT_UNSUPPORTED_CERT, 0);
goto done;
}
if (!l_key_get_info(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5,
L_CHECKSUM_NONE, &tls->peer_pubkey_size,
&dummy)) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
goto done;
}
tls->peer_pubkey_size /= 8;
if (tls->server)
tls->state = TLS_HANDSHAKE_WAIT_KEY_EXCHANGE;
else
tls->state = TLS_HANDSHAKE_WAIT_HELLO_DONE;
goto done;
decode_error:
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
done:
if (ca_cert)
l_free(ca_cert);
tls_cert_free_certchain(certchain);
}
static void tls_handle_certificate_request(struct l_tls *tls,
const uint8_t *buf, size_t len)
{
int cert_type_len, signature_hash_len, dn_len, i;
enum handshake_hash_type first_supported, hash;
const uint8_t *signature_hash_data;
uint8_t hash_id;
tls->cert_requested = 1;
cert_type_len = *buf++;
if (len < (size_t) 1 + cert_type_len + 2)
goto decode_error;
/* Skip certificate_types */
buf += cert_type_len;
len -= 1 + cert_type_len;
/*
* TODO: parse and save certificate_types,
* supported_signature_algorithms and certificate_authorities
* lists for use in tls_send_certificate.
*/
if (tls->negotiated_version >= TLS_V12) {
/*
* This only makes sense as a variable-length field, assume
* there's a typo in RFC5246 7.4.4 here.
*/
signature_hash_len = l_get_be16(buf);
signature_hash_data = buf + 2;
if (len < (size_t) 2 + signature_hash_len + 2 ||
(signature_hash_len & 1))
goto decode_error;
len -= 2 + signature_hash_len;
buf += 2 + signature_hash_len;
/*
* In 1.2 SHA256 is the default because that is most likely
* to be supported in all the scenarios and optimal because
* SHA256 is required independently for the Finished hash
* meaning that we'll just need one hash type instead of
* two. If not available fall back to the first common
* hash algorithm.
*/
first_supported = -1;
for (i = 0; i < signature_hash_len; i += 2) {
hash_id = signature_hash_data[i + 0];
/* Ignore hash types for signatures other than ours */
if (signature_hash_data[i + 1] != tls_rsa.id)
continue;
if (hash_id == tls_handshake_hash_data[
HANDSHAKE_HASH_SHA256].tls_id)
break;
if ((int) first_supported != -1)
continue;
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
if (hash_id == tls_handshake_hash_data[hash].
tls_id &&
tls->handshake_hash[hash]) {
first_supported = hash;
break;
}
}
if (i < signature_hash_len)
tls->signature_hash = HANDSHAKE_HASH_SHA256;
else if ((int) first_supported != -1)
tls->signature_hash = first_supported;
else {
tls_disconnect(tls, TLS_ALERT_UNSUPPORTED_CERT, 0);
return;
}
/*
* We can now safely stop maintaining handshake message
* hashes other than SHA256 and the one selected for
* signing.
*/
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
if (hash != HANDSHAKE_HASH_SHA256 &&
hash != tls->signature_hash)
tls_drop_handshake_hash(tls, hash);
}
dn_len = l_get_be16(buf);
if ((size_t) 2 + dn_len != len)
goto decode_error;
return;
decode_error:
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
}
static void tls_handle_server_hello_done(struct l_tls *tls,
const uint8_t *buf, size_t len)
{
if (len) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
return;
}
if (tls->cert_requested)
if (!tls_send_certificate(tls))
return;
if (!tls->pending.cipher_suite->key_xchg->send_client_key_exchange(tls))
return;
if (tls->cert_sent)
if (!tls_send_certificate_verify(tls))
return;
tls_send_change_cipher_spec(tls);
if (!tls_change_cipher_spec(tls, 1)) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
return;
}
tls_send_finished(tls);
tls->state = TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC;
}
static void tls_handle_rsa_client_key_xchg(struct l_tls *tls,
const uint8_t *buf, size_t len)
{
uint8_t pre_master_secret[48], random_secret[46];
ssize_t bytes_decrypted;
if (!tls->priv_key || !tls->priv_key_size) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
TLS_ALERT_BAD_CERT);
return;
}
if (len != tls->priv_key_size + 2) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
return;
}
len = l_get_be16(buf);
if (len != tls->priv_key_size) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
return;
}
bytes_decrypted = l_key_decrypt(tls->priv_key, L_KEY_RSA_PKCS1_V1_5,
L_CHECKSUM_NONE, buf + 2,
pre_master_secret, tls->priv_key_size,
48);
/*
* Assume correct premaster secret client version which according
* to the TLS1.2 spec is unlikely in client implementations SSLv3
* and prior. Spec suggests either not supporting them or adding
* a configurable override for <= SSLv3 clients. For now we have
* no need to support them.
*
* On any decode error randomise the Pre Master Secret as per the
* countermeasures in 7.4.7.1 and don't generate any alerts.
*/
l_getrandom(random_secret, 46);
pre_master_secret[0] = tls->client_version >> 8;
pre_master_secret[1] = tls->client_version >> 0;
if (bytes_decrypted != 48)
memcpy(pre_master_secret + 2, random_secret, 46);
tls_generate_master_secret(tls, pre_master_secret, 48);
memset(pre_master_secret, 0, 48);
memset(random_secret, 0, 46);
}
static bool tls_get_prev_digest_by_id(struct l_tls *tls, uint8_t hash_id,
uint8_t *out, size_t *out_len,
enum l_checksum_type *type)
{
enum handshake_hash_type hash;
size_t len;
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
if (tls_handshake_hash_data[hash].tls_id == hash_id &&
tls->handshake_hash[hash]) {
len = tls_handshake_hash_data[hash].length;
memcpy(out, tls->prev_digest[hash], len);
if (out_len)
*out_len = len;
if (type)
*type = tls_handshake_hash_data[hash].l_id;
return len;
}
return 0;
}
static void tls_handle_certificate_verify(struct l_tls *tls,
const uint8_t *buf, size_t len)
{
int i;
if (!tls->pending.cipher_suite->key_xchg->verify(tls, buf, len,
tls_get_prev_digest_by_id))
return;
/* Stop maintaining handshake message hashes other than SHA256. */
if (tls->negotiated_version >= TLS_V12)
for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
if (i != HANDSHAKE_HASH_SHA256)
tls_drop_handshake_hash(tls, i);
/*
* The client's certificate is now verified based on the following
* logic:
* - If we received an (expected) Certificate Verify, we must have
* sent a Certificate Request.
* - If we sent a Certificate Request that's because
* tls->ca_cert_path is non-NULL.
* - If tls->ca_cert_path is non-NULL then tls_handle_certificate
* will have checked the whole certificate chain to be valid and
* additionally trusted by our CA if known.
* - Additionally cipher_suite->key_xchg->verify has just confirmed
* that the peer owns the end-entity certificate because it was
* able to sign the contents of the handshake messages and that
* signature could be verified with the public key from that
* certificate.
*/
tls->peer_authenticated = true;
tls->state = TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC;
}
static void tls_finished(struct l_tls *tls)
{
char *peer_identity = NULL;
/* Free up the resources used in the handshake */
tls_reset_handshake(tls);
tls->state = TLS_HANDSHAKE_DONE;
tls->ready = true;
tls->ready_handle(peer_identity, tls->user_data);
tls_cleanup_handshake(tls);
if (peer_identity)
l_free(peer_identity);
}
static void tls_handle_handshake(struct l_tls *tls, int type,
const uint8_t *buf, size_t len)
{
switch (type) {
case TLS_HELLO_REQUEST:
if (tls->server) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
if (len != 0) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
break;
}
/*
* May be sent by the server at any time but "SHOULD be ignored
* by the client if it arrives in the middle of a handshake"
* and "MAY be ignored by the client if it does not wish to
* renegotiate a session".
*/
break;
case TLS_CLIENT_HELLO:
if (!tls->server) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
if (tls->state != TLS_HANDSHAKE_WAIT_HELLO &&
tls->state != TLS_HANDSHAKE_DONE) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
tls_handle_client_hello(tls, buf, len);
break;
case TLS_SERVER_HELLO:
if (tls->server) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
if (tls->state != TLS_HANDSHAKE_WAIT_HELLO) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
tls_handle_server_hello(tls, buf, len);
break;
case TLS_CERTIFICATE:
if (tls->state != TLS_HANDSHAKE_WAIT_CERTIFICATE) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
tls_handle_certificate(tls, buf, len);
break;
case TLS_CERTIFICATE_REQUEST:
/*
* Server sends this optionally so in the WAIT_HELLO_DONE
* state we accept either this or a Server Hello Done (below).
*/
if (tls->state != TLS_HANDSHAKE_WAIT_HELLO_DONE ||
tls->cert_requested ||
!tls->pending.cipher_suite->key_xchg->
certificate_check) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
tls_handle_certificate_request(tls, buf, len);
break;
case TLS_SERVER_HELLO_DONE:
if (tls->state != TLS_HANDSHAKE_WAIT_HELLO_DONE) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
tls_handle_server_hello_done(tls, buf, len);
break;
case TLS_CERTIFICATE_VERIFY:
if (tls->state != TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
tls_handle_certificate_verify(tls, buf, len);
break;
case TLS_CLIENT_KEY_EXCHANGE:
if (!tls->server) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
if (tls->state != TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
tls->pending.cipher_suite->key_xchg->handle_client_key_exchange(
tls, buf, len);
/*
* If we accepted a client Certificate message with a
* certificate that has signing capability (TODO: check
* usage bitmask), Certiifcate Verify is received next. It
* sounds as if this is mandatory for the client although
* this isn't 100% clear.
*/
if (tls->peer_pubkey)
tls->state = TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY;
else
tls->state = TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC;
break;
case TLS_FINISHED:
if (tls->state != TLS_HANDSHAKE_WAIT_FINISHED) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
break;
}
if (!tls_verify_finished(tls, buf, len))
break;
if (tls->server) {
tls_send_change_cipher_spec(tls);
if (!tls_change_cipher_spec(tls, 1)) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR,
0);
break;
}
tls_send_finished(tls);
}
/*
* On the client, the server's certificate is only now
* verified, based on the following logic:
* - tls->ca_cert_path is non-NULL so tls_handle_certificate
* (always called on the client) must have veritifed the
* server's certificate chain to be valid and additionally
* trusted by our CA.
* - the correct receival of this Finished message confirms
* that the peer owns the end-entity certificate because
* it was able to decrypt the master secret which we had
* encrypted with the public key from that certificate, and
* the posession of the master secret in turn is verified
* by both the successful decryption and the MAC of this
* message (either should be enough).
*/
if (!tls->server && tls->cipher_suite[0]->key_xchg->
certificate_check &&
tls->ca_cert_path)
tls->peer_authenticated = true;
tls_finished(tls);
break;
default:
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
}
}
LIB_EXPORT struct l_tls *l_tls_new(bool server,
l_tls_write_cb_t app_data_handler,
l_tls_write_cb_t tx_handler,
l_tls_ready_cb_t ready_handler,
l_tls_disconnect_cb_t disconnect_handler,
void *user_data)
{
struct l_tls *tls;
tls = l_new(struct l_tls, 1);
tls->server = server;
tls->rx = app_data_handler;
tls->tx = tx_handler;
tls->ready_handle = ready_handler;
tls->disconnected = disconnect_handler;
tls->user_data = user_data;
tls->signature_hash = HANDSHAKE_HASH_SHA256;
/* If we're the client, start the handshake right away */
if (!tls->server) {
if (!tls_init_handshake_hash(tls)) {
l_free(tls);
return NULL;
}
tls_send_client_hello(tls);
}
tls->state = TLS_HANDSHAKE_WAIT_HELLO;
return tls;
}
LIB_EXPORT void l_tls_free(struct l_tls *tls)
{
enum handshake_hash_type hash;
if (unlikely(!tls))
return;
l_tls_set_cacert(tls, NULL);
l_tls_set_auth_data(tls, NULL, NULL, NULL);
tls_reset_handshake(tls);
tls_cleanup_handshake(tls);
tls_reset_cipher_spec(tls, 0);
tls_reset_cipher_spec(tls, 1);
if (tls->record_buf)
l_free(tls->record_buf);
if (tls->message_buf)
l_free(tls->message_buf);
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
tls_drop_handshake_hash(tls, hash);
l_free(tls);
}
LIB_EXPORT void l_tls_write(struct l_tls *tls, const uint8_t *data, size_t len)
{
if (unlikely(!tls->ready)) {
return;
}
tls_tx_record(tls, TLS_CT_APPLICATION_DATA, data, len);
}
bool tls_handle_message(struct l_tls *tls, const uint8_t *message,
int len, enum tls_content_type type, uint16_t version)
{
enum handshake_hash_type hash;
switch (type) {
case TLS_CT_CHANGE_CIPHER_SPEC:
if (len != 1 || message[0] != 0x01) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
return false;
}
if (tls->state != TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
return false;
}
if (!tls_change_cipher_spec(tls, 0)) {
tls_disconnect(tls, TLS_ALERT_INTERNAL_ERROR, 0);
return false;
}
tls->state = TLS_HANDSHAKE_WAIT_FINISHED;
return true;
case TLS_CT_ALERT:
/* Verify AlertLevel */
if (message[0] != 0x01 && message[0] != 0x02) {
tls_disconnect(tls, TLS_ALERT_DECODE_ERROR, 0);
return false;
}
/*
* On a fatal alert we are obligated to respond with a
* fatal alert and disconnect but also not complain if
* the connection has been torn down by the peer before
* we were able to send our alert. However on a non-fatal
* alert (warning) we're also allowed to panic and send
* a fatal alert, then disconnect, so we do that
* regardless of the alert level.
*/
tls_disconnect(tls, TLS_ALERT_CLOSE_NOTIFY, message[1]);
return false;
case TLS_CT_HANDSHAKE:
/* Start hashing the handshake contents on first message */
if (tls->server && message[0] == TLS_CLIENT_HELLO &&
(tls->state == TLS_HANDSHAKE_WAIT_HELLO ||
tls->state != TLS_HANDSHAKE_DONE))
if (!tls_init_handshake_hash(tls))
return false;
/*
* Corner case: When handling a Certificate Verify or a
* Finished message we need access to the messages hash from
* before this message was transmitted on the Tx side so we
* can verify it matches the hash the sender included in the
* message. We save it here for that purpose. Everywhere
* else we need to update the hash before handling the new
* message because 1. we may need the new hash to build our
* own Certificate Verify or Finished messages, and 2. we
* update the message hash with newly transmitted messages
* inside tls_tx_handshake which may be called as part of
* handling incoming message, and if we didn't call
* l_checksum_update before, the calls would end up being
* out of order.
*/
if (message[0] == TLS_CERTIFICATE_VERIFY ||
message[0] == TLS_FINISHED)
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) {
if (!tls->handshake_hash[hash])
continue;
tls_get_handshake_hash(tls, hash,
tls->prev_digest[hash]);
}
/*
* RFC 5246, Section 7.4.1.1:
* This message MUST NOT be included in the message hashes
* that are maintained throughout the handshake and used in
* the Finished messages and the certificate verify message.
*/
if (message[0] != TLS_HELLO_REQUEST)
for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) {
if (!tls->handshake_hash[hash])
continue;
l_checksum_update(tls->handshake_hash[hash],
message, len);
}
tls_handle_handshake(tls, message[0],
message + TLS_HANDSHAKE_HEADER_SIZE,
len - TLS_HANDSHAKE_HEADER_SIZE);
return true;
case TLS_CT_APPLICATION_DATA:
if (!tls->ready) {
tls_disconnect(tls, TLS_ALERT_UNEXPECTED_MESSAGE, 0);
return false;
}
if (!len)
return true;
tls->rx(message, len, tls->user_data);
return true;
}
return false;
}
LIB_EXPORT void l_tls_close(struct l_tls *tls)
{
tls_disconnect(tls, TLS_ALERT_CLOSE_NOTIFY, 0);
}
LIB_EXPORT void l_tls_set_cacert(struct l_tls *tls, const char *ca_cert_path)
{
if (tls->ca_cert_path) {
l_free(tls->ca_cert_path);
tls->ca_cert_path = NULL;
}
if (ca_cert_path)
tls->ca_cert_path = l_strdup(ca_cert_path);
}
LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls, const char *cert_path,
const char *priv_key_path,
const char *priv_key_passphrase)
{
if (tls->cert_path) {
l_free(tls->cert_path);
tls->cert_path = NULL;
}
if (tls->priv_key) {
l_key_free(tls->priv_key);
tls->priv_key = NULL;
tls->priv_key_size = 0;
}
if (priv_key_path) {
uint8_t *priv_key;
bool is_public = true;
priv_key = l_pem_load_private_key(priv_key_path,
priv_key_passphrase,
NULL,
&tls->priv_key_size);
if (!priv_key)
return false;
tls->priv_key = l_key_new(L_KEY_RSA, priv_key,
tls->priv_key_size);
memset(priv_key, 0, tls->priv_key_size);
l_free(priv_key);
if (!l_key_get_info(tls->priv_key, L_KEY_RSA_PKCS1_V1_5,
L_CHECKSUM_NONE, &tls->priv_key_size,
&is_public) || is_public) {
l_key_free(tls->priv_key);
tls->priv_key = NULL;
tls->priv_key_size = 0;
return false;
}
tls->priv_key_size /= 8;
}
if (cert_path)
tls->cert_path = l_strdup(cert_path);
return true;
}
LIB_EXPORT const char *l_tls_alert_to_str(enum l_tls_alert_desc desc)
{
switch (desc) {
case TLS_ALERT_CLOSE_NOTIFY:
return "close_notify";
case TLS_ALERT_UNEXPECTED_MESSAGE:
return "unexpected_message";
case TLS_ALERT_BAD_RECORD_MAC:
return "bad_record_mac";
case TLS_ALERT_DECRYPT_FAIL_RESERVED:
return "decryption_failure_RESERVED";
case TLS_ALERT_RECORD_OVERFLOW:
return "record_overflow";
case TLS_ALERT_DECOMPRESS_FAIL:
return "decompression_failure";
case TLS_ALERT_HANDSHAKE_FAIL:
return "handshake_failure";
case TLS_ALERT_NO_CERT_RESERVED:
return "no_certificate_RESERVED";
case TLS_ALERT_BAD_CERT:
return "bad_certificate";
case TLS_ALERT_UNSUPPORTED_CERT:
return "unsupported_certificate";
case TLS_ALERT_CERT_REVOKED:
return "certificate_revoked";
case TLS_ALERT_CERT_EXPIRED:
return "certificate_expired";
case TLS_ALERT_CERT_UNKNOWN:
return "certificate_unknown";
case TLS_ALERT_ILLEGAL_PARAM:
return "illegal_parameter";
case TLS_ALERT_UNKNOWN_CA:
return "unknown_ca";
case TLS_ALERT_ACCESS_DENIED:
return "access_denied";
case TLS_ALERT_DECODE_ERROR:
return "decode_error";
case TLS_ALERT_DECRYPT_ERROR:
return "decrypt_error";
case TLS_ALERT_EXPORT_RES_RESERVED:
return "export_restriction_RESERVED";
case TLS_ALERT_PROTOCOL_VERSION:
return "protocol_version";
case TLS_ALERT_INSUFFICIENT_SECURITY:
return "insufficient_security";
case TLS_ALERT_INTERNAL_ERROR:
return "internal_error";
case TLS_ALERT_USER_CANCELED:
return "user_canceled";
case TLS_ALERT_NO_RENEGOTIATION:
return "no_renegotiation";
case TLS_ALERT_UNSUPPORTED_EXTENSION:
return "unsupported_extension";
}
return NULL;
}
/* X509 Certificates and Certificate Chains */
#define X509_CERTIFICATE_POS 0
#define X509_TBSCERTIFICATE_POS 0
#define X509_TBSCERT_VERSION_POS 0
#define X509_TBSCERT_SERIAL_POS 1
#define X509_TBSCERT_SIGNATURE_POS 2
#define X509_ALGORITHM_ID_ALGORITHM_POS 0
#define X509_ALGORITHM_ID_PARAMS_POS 1
#define X509_TBSCERT_ISSUER_DN_POS 3
#define X509_TBSCERT_VALIDITY_POS 4
#define X509_TBSCERT_SUBJECT_DN_POS 5
#define X509_TBSCERT_SUBJECT_KEY_POS 6
#define X509_SUBJECT_KEY_ALGORITHM_POS 0
#define X509_SUBJECT_KEY_VALUE_POS 1
#define X509_TBSCERT_ISSUER_UID_POS 7
#define X509_TBSCERT_SUBJECT_UID_POS 8
#define X509_TBSCERT_EXTENSIONS_POS 9
#define X509_SIGNATURE_ALGORITHM_POS 1
#define X509_SIGNATURE_VALUE_POS 2
struct tls_cert *tls_cert_load_file(const char *filename)
{
uint8_t *der;
size_t len;
struct tls_cert *cert;
der = l_pem_load_certificate(filename, &len);
if (!der)
return NULL;
if (!len || der[0] != ASN1_ID_SEQUENCE) {
l_free(der);
return NULL;
}
cert = l_malloc(sizeof(struct tls_cert) + len);
cert->size = len;
cert->issuer = NULL;
memcpy(cert->asn1, der, len);
l_free(der);
return cert;
}
bool tls_cert_find_certchain(struct tls_cert *cert,
const char *cacert_filename)
{
return true;
}
static const struct pkcs1_encryption_oid {
enum tls_cert_key_type key_type;
struct asn1_oid oid;
} pkcs1_encryption_oids[] = {
{ /* rsaEncryption */
TLS_CERT_KEY_RSA,
{ 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 } },
},
};
static void tls_key_cleanup(struct l_key **p)
{
l_key_free_norevoke(*p);
}
static bool tls_cert_verify_with_keyring(struct tls_cert *cert,
struct l_keyring *ring,
struct tls_cert *root,
struct l_keyring *trusted)
{
if (!cert)
return true;
/*
* RFC5246 7.4.2:
* "Because certificate validation requires that root keys be
* distributed independently, the self-signed certificate that
* specifies the root certificate authority MAY be omitted from
* the chain, under the assumption that the remote end must
* already possess it in order to validate it in any case."
*/
if (!cert->issuer && root && cert->size == root->size &&
!memcmp(cert->asn1, root->asn1, root->size))
return true;
if (tls_cert_verify_with_keyring(cert->issuer, ring, root, trusted)) {
L_AUTO_CLEANUP_VAR(struct l_key *, key, tls_key_cleanup);
key = l_key_new(L_KEY_RSA, cert->asn1, cert->size);
if (!key)
return false;
if (!l_keyring_link(ring, key))
return false;
if (trusted || cert->issuer)
return true;
/*
* If execution reaches this point, it's known that:
* * No trusted root key was supplied, so the chain is only
* being checked against its own root
* * The keyring 'ring' is not restricted yet
* * The chain's root cert was just linked in to the
* previously empty keyring 'ring'.
*
* By restricting 'ring' now, the rest of the certs in
* the chain will have their signature validated using 'key'
* as the root.
*/
return l_keyring_restrict(ring, L_KEYRING_RESTRICT_ASYM_CHAIN,
trusted);
}
return false;
}
static void tls_keyring_cleanup(struct l_keyring **p)
{
l_keyring_free(*p);
}
bool tls_cert_verify_certchain(struct tls_cert *certchain,
struct tls_cert *ca_cert)
{
L_AUTO_CLEANUP_VAR(struct l_keyring *, ca_ring, tls_keyring_cleanup);
L_AUTO_CLEANUP_VAR(struct l_keyring *, verify_ring,
tls_keyring_cleanup);
ca_ring = NULL;
verify_ring = NULL;
if (ca_cert) {
L_AUTO_CLEANUP_VAR(struct l_key *, ca_key, tls_key_cleanup);
ca_key = NULL;
ca_ring = l_keyring_new();
if (!ca_ring)
return false;
ca_key = l_key_new(L_KEY_RSA, ca_cert->asn1, ca_cert->size);
if (!ca_key || !l_keyring_link(ca_ring, ca_key))
return false;
}
verify_ring = l_keyring_new();
if (!verify_ring)
return false;
/*
* If a CA cert was supplied, restrict verify_ring now so
* everything else in certchain is validated against the CA.
* Otherwise, verify_ring will be restricted after the root of
* certchain is added to verify_ring by
* tls_cert_verify_with_keyring().
*/
if (ca_ring && !l_keyring_restrict(verify_ring,
L_KEYRING_RESTRICT_ASYM_CHAIN,
ca_ring)) {
return false;
}
return tls_cert_verify_with_keyring(certchain, verify_ring, ca_cert,
ca_ring);
}
void tls_cert_free_certchain(struct tls_cert *cert)
{
struct tls_cert *next;
while (cert) {
next = cert->issuer;
l_free(cert);
cert = next;
}
}
enum tls_cert_key_type tls_cert_get_pubkey_type(struct tls_cert *cert)
{
const uint8_t *key_type;
size_t key_type_len;
int i;
key_type = asn1_der_find_elem_by_path(cert->asn1, cert->size,
ASN1_ID_OID, &key_type_len,
X509_CERTIFICATE_POS,
X509_TBSCERTIFICATE_POS,
X509_TBSCERT_SUBJECT_KEY_POS,
X509_SUBJECT_KEY_ALGORITHM_POS,
X509_ALGORITHM_ID_ALGORITHM_POS,
-1);
if (!key_type)
return TLS_CERT_KEY_UNKNOWN;
for (i = 0; i < (int) L_ARRAY_SIZE(pkcs1_encryption_oids); i++)
if (asn1_oid_eq(&pkcs1_encryption_oids[i].oid,
key_type_len, key_type))
break;
if (i == L_ARRAY_SIZE(pkcs1_encryption_oids))
return TLS_CERT_KEY_UNKNOWN;
return pkcs1_encryption_oids[i].key_type;
}