libtls: Implement TLS 1.3 handshake on client-side
The code is a minimal handshake with the HelloRetryRequest message implementation missing. Can be tested with an OpenSSL server running TLS 1.3. The server must be at least version 1.1.1 (September 2018). Co-authored-by: ryru <pascal.knecht@hsr.ch>
This commit is contained in:
parent
02d7405512
commit
7a2b02667c
|
@ -92,6 +92,7 @@ static int run_client(host_t *host, identification_t *server,
|
||||||
|
|
||||||
while (times == -1 || times-- > 0)
|
while (times == -1 || times-- > 0)
|
||||||
{
|
{
|
||||||
|
/* Open IPv4 socket */
|
||||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
{
|
{
|
||||||
|
@ -101,11 +102,21 @@ static int run_client(host_t *host, identification_t *server,
|
||||||
if (connect(fd, host->get_sockaddr(host),
|
if (connect(fd, host->get_sockaddr(host),
|
||||||
*host->get_sockaddr_len(host)) == -1)
|
*host->get_sockaddr_len(host)) == -1)
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "connecting to %#H failed: %s", host, strerror(errno));
|
/* Check if the socket should use IPv6 instead */
|
||||||
close(fd);
|
fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
return 1;
|
{
|
||||||
|
if (connect(fd, host->get_sockaddr(host),
|
||||||
|
*host->get_sockaddr_len(host)) == -1)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "connecting to %#H failed: %s", host, strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
tls = tls_socket_create(FALSE, server, client, fd, cache, TLS_1_2, TRUE);
|
tls = tls_socket_create(FALSE, server, client, fd, cache,
|
||||||
|
TLS_1_3, TRUE);
|
||||||
if (!tls)
|
if (!tls)
|
||||||
{
|
{
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -337,11 +348,17 @@ int main(int argc, char *argv[])
|
||||||
usage(stderr, argv[0]);
|
usage(stderr, argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
host = host_create_from_dns(address, 0, port);
|
/* Try to connect with IPv4 first*/
|
||||||
|
host = host_create_from_dns(address, AF_INET, port);
|
||||||
if (!host)
|
if (!host)
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "resolving hostname %s failed", address);
|
/* If it fails, try IPv6*/
|
||||||
return 1;
|
host = host_create_from_dns(address, AF_INET6, port);
|
||||||
|
if (!host)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "resolving hostname %s failed", address);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
server = identification_create_from_string(address);
|
server = identification_create_from_string(address);
|
||||||
cache = tls_cache_create(100, 30);
|
cache = tls_cache_create(100, 30);
|
||||||
|
|
114
src/libtls/tls.c
114
src/libtls/tls.c
|
@ -26,12 +26,13 @@
|
||||||
|
|
||||||
ENUM_BEGIN(tls_version_names, SSL_2_0, SSL_2_0,
|
ENUM_BEGIN(tls_version_names, SSL_2_0, SSL_2_0,
|
||||||
"SSLv2");
|
"SSLv2");
|
||||||
ENUM_NEXT(tls_version_names, SSL_3_0, TLS_1_2, SSL_2_0,
|
ENUM_NEXT(tls_version_names, SSL_3_0, TLS_1_3, SSL_2_0,
|
||||||
"SSLv3",
|
"SSLv3",
|
||||||
"TLS 1.0",
|
"TLS 1.0",
|
||||||
"TLS 1.1",
|
"TLS 1.1",
|
||||||
"TLS 1.2");
|
"TLS 1.2",
|
||||||
ENUM_END(tls_version_names, TLS_1_2);
|
"TLS 1.3");
|
||||||
|
ENUM_END(tls_version_names, TLS_1_3);
|
||||||
|
|
||||||
ENUM(tls_content_type_names, TLS_CHANGE_CIPHER_SPEC, TLS_APPLICATION_DATA,
|
ENUM(tls_content_type_names, TLS_CHANGE_CIPHER_SPEC, TLS_APPLICATION_DATA,
|
||||||
"ChangeCipherSpec",
|
"ChangeCipherSpec",
|
||||||
|
@ -40,12 +41,22 @@ ENUM(tls_content_type_names, TLS_CHANGE_CIPHER_SPEC, TLS_APPLICATION_DATA,
|
||||||
"ApplicationData",
|
"ApplicationData",
|
||||||
);
|
);
|
||||||
|
|
||||||
ENUM_BEGIN(tls_handshake_type_names, TLS_HELLO_REQUEST, TLS_SERVER_HELLO,
|
ENUM_BEGIN(tls_handshake_type_names, TLS_HELLO_REQUEST, TLS_HELLO_REQUEST,
|
||||||
"HelloRequest",
|
"HelloRequest");
|
||||||
"ClientHello",
|
|
||||||
"ServerHello");
|
|
||||||
ENUM_NEXT(tls_handshake_type_names,
|
ENUM_NEXT(tls_handshake_type_names,
|
||||||
TLS_CERTIFICATE, TLS_CLIENT_KEY_EXCHANGE, TLS_SERVER_HELLO,
|
TLS_CLIENT_HELLO, TLS_HELLO_RETRY_REQUEST, TLS_HELLO_REQUEST,
|
||||||
|
"ClientHello",
|
||||||
|
"ServerHello",
|
||||||
|
"HelloVerifyRequest",
|
||||||
|
"NewSessionTicket",
|
||||||
|
"EndOfEarlyData",
|
||||||
|
"HelloRetryRequest");
|
||||||
|
ENUM_NEXT(tls_handshake_type_names,
|
||||||
|
TLS_ENCRYPTED_EXTENSIONS, TLS_ENCRYPTED_EXTENSIONS,
|
||||||
|
TLS_HELLO_RETRY_REQUEST,
|
||||||
|
"EncryptedExtensions");
|
||||||
|
ENUM_NEXT(tls_handshake_type_names,
|
||||||
|
TLS_CERTIFICATE, TLS_CLIENT_KEY_EXCHANGE, TLS_ENCRYPTED_EXTENSIONS,
|
||||||
"Certificate",
|
"Certificate",
|
||||||
"ServerKeyExchange",
|
"ServerKeyExchange",
|
||||||
"CertificateRequest",
|
"CertificateRequest",
|
||||||
|
@ -53,9 +64,16 @@ ENUM_NEXT(tls_handshake_type_names,
|
||||||
"CertificateVerify",
|
"CertificateVerify",
|
||||||
"ClientKeyExchange");
|
"ClientKeyExchange");
|
||||||
ENUM_NEXT(tls_handshake_type_names,
|
ENUM_NEXT(tls_handshake_type_names,
|
||||||
TLS_FINISHED, TLS_FINISHED, TLS_CLIENT_KEY_EXCHANGE,
|
TLS_FINISHED, TLS_KEY_UPDATE, TLS_CLIENT_KEY_EXCHANGE,
|
||||||
"Finished");
|
"Finished",
|
||||||
ENUM_END(tls_handshake_type_names, TLS_FINISHED);
|
"CertificateUrl",
|
||||||
|
"CertificateStatus",
|
||||||
|
"SupplementalData",
|
||||||
|
"KeyUpdate");
|
||||||
|
ENUM_NEXT(tls_handshake_type_names,
|
||||||
|
TLS_MESSAGE_HASH, TLS_MESSAGE_HASH, TLS_KEY_UPDATE,
|
||||||
|
"MessageHash");
|
||||||
|
ENUM_END(tls_handshake_type_names, TLS_MESSAGE_HASH);
|
||||||
|
|
||||||
ENUM_BEGIN(tls_extension_names, TLS_EXT_SERVER_NAME, TLS_EXT_STATUS_REQUEST,
|
ENUM_BEGIN(tls_extension_names, TLS_EXT_SERVER_NAME, TLS_EXT_STATUS_REQUEST,
|
||||||
"server name",
|
"server name",
|
||||||
|
@ -65,17 +83,42 @@ ENUM_BEGIN(tls_extension_names, TLS_EXT_SERVER_NAME, TLS_EXT_STATUS_REQUEST,
|
||||||
"truncated hmac",
|
"truncated hmac",
|
||||||
"status request");
|
"status request");
|
||||||
ENUM_NEXT(tls_extension_names,
|
ENUM_NEXT(tls_extension_names,
|
||||||
TLS_EXT_ELLIPTIC_CURVES, TLS_EXT_EC_POINT_FORMATS,
|
TLS_EXT_SUPPORTED_GROUPS, TLS_EXT_EC_POINT_FORMATS,
|
||||||
TLS_EXT_STATUS_REQUEST,
|
TLS_EXT_STATUS_REQUEST,
|
||||||
"elliptic curves",
|
"supported groups",
|
||||||
"ec point formats");
|
"ec point formats");
|
||||||
ENUM_NEXT(tls_extension_names,
|
ENUM_NEXT(tls_extension_names,
|
||||||
TLS_EXT_SIGNATURE_ALGORITHMS, TLS_EXT_SIGNATURE_ALGORITHMS,
|
TLS_EXT_SIGNATURE_ALGORITHMS,
|
||||||
|
TLS_EXT_APPLICATION_LAYER_PROTOCOL_NEGOTIATION,
|
||||||
TLS_EXT_EC_POINT_FORMATS,
|
TLS_EXT_EC_POINT_FORMATS,
|
||||||
"signature algorithms");
|
"signature algorithms",
|
||||||
|
"use rtp",
|
||||||
|
"heartbeat",
|
||||||
|
"application layer protocol negotiation");
|
||||||
|
ENUM_NEXT(tls_extension_names,
|
||||||
|
TLS_CLIENT_CERTIFICATE_TYPE, TLS_SERVER_CERTIFICATE_TYPE,
|
||||||
|
TLS_EXT_APPLICATION_LAYER_PROTOCOL_NEGOTIATION,
|
||||||
|
"client certificate type",
|
||||||
|
"server certificate type");
|
||||||
|
ENUM_NEXT(tls_extension_names,
|
||||||
|
TLS_EXT_PRE_SHARED_KEY, TLS_EXT_PSK_KEY_EXCHANGE_MODES,
|
||||||
|
TLS_SERVER_CERTIFICATE_TYPE,
|
||||||
|
"pre-shared key",
|
||||||
|
"early data",
|
||||||
|
"supported versions",
|
||||||
|
"cookie",
|
||||||
|
"psk key exchange modes");
|
||||||
|
ENUM_NEXT(tls_extension_names,
|
||||||
|
TLS_EXT_CERTIFICATE_AUTHORITIES, TLS_EXT_KEY_SHARE,
|
||||||
|
TLS_EXT_PSK_KEY_EXCHANGE_MODES,
|
||||||
|
"certificate authorities",
|
||||||
|
"oid filters",
|
||||||
|
"post-handshake auth",
|
||||||
|
"signature algorithms cert",
|
||||||
|
"key-share");
|
||||||
ENUM_NEXT(tls_extension_names,
|
ENUM_NEXT(tls_extension_names,
|
||||||
TLS_EXT_RENEGOTIATION_INFO, TLS_EXT_RENEGOTIATION_INFO,
|
TLS_EXT_RENEGOTIATION_INFO, TLS_EXT_RENEGOTIATION_INFO,
|
||||||
TLS_EXT_SIGNATURE_ALGORITHMS,
|
TLS_EXT_KEY_SHARE,
|
||||||
"renegotiation info");
|
"renegotiation info");
|
||||||
ENUM_END(tls_extension_names, TLS_EXT_RENEGOTIATION_INFO);
|
ENUM_END(tls_extension_names, TLS_EXT_RENEGOTIATION_INFO);
|
||||||
|
|
||||||
|
@ -107,9 +150,14 @@ struct private_tls_t {
|
||||||
bool is_server;
|
bool is_server;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Negotiated TLS version
|
* Negotiated TLS version and maximum supported TLS version
|
||||||
*/
|
*/
|
||||||
tls_version_t version;
|
tls_version_t version_max;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimal supported TLS version
|
||||||
|
*/
|
||||||
|
tls_version_t version_min;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TLS stack purpose, as given to constructor
|
* TLS stack purpose, as given to constructor
|
||||||
|
@ -300,7 +348,14 @@ METHOD(tls_t, build, status_t,
|
||||||
{
|
{
|
||||||
case NEED_MORE:
|
case NEED_MORE:
|
||||||
record.type = type;
|
record.type = type;
|
||||||
htoun16(&record.version, this->version);
|
if (this->version_max < TLS_1_3)
|
||||||
|
{
|
||||||
|
htoun16(&record.version, this->version_max);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
htoun16(&record.version, TLS_1_2);
|
||||||
|
}
|
||||||
htoun16(&record.length, data.len);
|
htoun16(&record.length, data.len);
|
||||||
this->output = chunk_cat("mcm", this->output,
|
this->output = chunk_cat("mcm", this->output,
|
||||||
chunk_from_thing(record), data);
|
chunk_from_thing(record), data);
|
||||||
|
@ -361,16 +416,22 @@ METHOD(tls_t, get_peer_id, identification_t*,
|
||||||
return this->handshake->get_peer_id(this->handshake);
|
return this->handshake->get_peer_id(this->handshake);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(tls_t, get_version, tls_version_t,
|
METHOD(tls_t, get_version_max, tls_version_t,
|
||||||
private_tls_t *this)
|
private_tls_t *this)
|
||||||
{
|
{
|
||||||
return this->version;
|
return this->version_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tls_t, get_version_min, tls_version_t,
|
||||||
|
private_tls_t *this)
|
||||||
|
{
|
||||||
|
return this->version_min;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(tls_t, set_version, bool,
|
METHOD(tls_t, set_version, bool,
|
||||||
private_tls_t *this, tls_version_t version)
|
private_tls_t *this, tls_version_t version)
|
||||||
{
|
{
|
||||||
if (version > this->version)
|
if (version > this->version_max)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -379,7 +440,8 @@ METHOD(tls_t, set_version, bool,
|
||||||
case TLS_1_0:
|
case TLS_1_0:
|
||||||
case TLS_1_1:
|
case TLS_1_1:
|
||||||
case TLS_1_2:
|
case TLS_1_2:
|
||||||
this->version = version;
|
case TLS_1_3:
|
||||||
|
this->version_max = version;
|
||||||
this->protection->set_version(this->protection, version);
|
this->protection->set_version(this->protection, version);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
case SSL_2_0:
|
case SSL_2_0:
|
||||||
|
@ -466,7 +528,8 @@ tls_t *tls_create(bool is_server, identification_t *server,
|
||||||
.is_server = _is_server,
|
.is_server = _is_server,
|
||||||
.get_server_id = _get_server_id,
|
.get_server_id = _get_server_id,
|
||||||
.get_peer_id = _get_peer_id,
|
.get_peer_id = _get_peer_id,
|
||||||
.get_version = _get_version,
|
.get_version_max = _get_version_max,
|
||||||
|
.get_version_min = _get_version_min,
|
||||||
.set_version = _set_version,
|
.set_version = _set_version,
|
||||||
.get_purpose = _get_purpose,
|
.get_purpose = _get_purpose,
|
||||||
.is_complete = _is_complete,
|
.is_complete = _is_complete,
|
||||||
|
@ -475,7 +538,8 @@ tls_t *tls_create(bool is_server, identification_t *server,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.is_server = is_server,
|
.is_server = is_server,
|
||||||
.version = TLS_1_2,
|
.version_max = TLS_1_3,
|
||||||
|
.version_min = TLS_1_0,
|
||||||
.application = application,
|
.application = application,
|
||||||
.purpose = purpose,
|
.purpose = purpose,
|
||||||
);
|
);
|
||||||
|
|
|
@ -52,6 +52,7 @@ enum tls_version_t {
|
||||||
TLS_1_0 = 0x0301,
|
TLS_1_0 = 0x0301,
|
||||||
TLS_1_1 = 0x0302,
|
TLS_1_1 = 0x0302,
|
||||||
TLS_1_2 = 0x0303,
|
TLS_1_2 = 0x0303,
|
||||||
|
TLS_1_3 = 0x0304,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,6 +82,11 @@ enum tls_handshake_type_t {
|
||||||
TLS_HELLO_REQUEST = 0,
|
TLS_HELLO_REQUEST = 0,
|
||||||
TLS_CLIENT_HELLO = 1,
|
TLS_CLIENT_HELLO = 1,
|
||||||
TLS_SERVER_HELLO = 2,
|
TLS_SERVER_HELLO = 2,
|
||||||
|
TLS_HELLO_VERIFY_REQUEST = 3,
|
||||||
|
TLS_NEW_SESSION_TICKET = 4,
|
||||||
|
TLS_END_OF_EARLY_DATA = 5,
|
||||||
|
TLS_HELLO_RETRY_REQUEST = 6,
|
||||||
|
TLS_ENCRYPTED_EXTENSIONS = 8,
|
||||||
TLS_CERTIFICATE = 11,
|
TLS_CERTIFICATE = 11,
|
||||||
TLS_SERVER_KEY_EXCHANGE = 12,
|
TLS_SERVER_KEY_EXCHANGE = 12,
|
||||||
TLS_CERTIFICATE_REQUEST = 13,
|
TLS_CERTIFICATE_REQUEST = 13,
|
||||||
|
@ -88,6 +94,11 @@ enum tls_handshake_type_t {
|
||||||
TLS_CERTIFICATE_VERIFY = 15,
|
TLS_CERTIFICATE_VERIFY = 15,
|
||||||
TLS_CLIENT_KEY_EXCHANGE = 16,
|
TLS_CLIENT_KEY_EXCHANGE = 16,
|
||||||
TLS_FINISHED = 20,
|
TLS_FINISHED = 20,
|
||||||
|
TLS_CERTIFICATE_URL = 21,
|
||||||
|
TLS_CERTIFICATE_STATUS = 22,
|
||||||
|
TLS_SUPPLEMENTAL_DATA = 23,
|
||||||
|
TLS_KEY_UPDATE = 24,
|
||||||
|
TLS_MESSAGE_HASH = 254,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,7 +125,7 @@ enum tls_purpose_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TLS Hello extension types.
|
* TLS Handshake extension types.
|
||||||
*/
|
*/
|
||||||
enum tls_extension_t {
|
enum tls_extension_t {
|
||||||
/** Server name the client wants to talk to */
|
/** Server name the client wants to talk to */
|
||||||
|
@ -129,12 +140,42 @@ enum tls_extension_t {
|
||||||
TLS_EXT_TRUNCATED_HMAC = 4,
|
TLS_EXT_TRUNCATED_HMAC = 4,
|
||||||
/** list of OCSP responders the client trusts */
|
/** list of OCSP responders the client trusts */
|
||||||
TLS_EXT_STATUS_REQUEST = 5,
|
TLS_EXT_STATUS_REQUEST = 5,
|
||||||
/** list of supported elliptic curves */
|
/** list of supported groups, in legacy tls: elliptic curves */
|
||||||
TLS_EXT_ELLIPTIC_CURVES = 10,
|
TLS_EXT_SUPPORTED_GROUPS = 10,
|
||||||
/** supported point formats */
|
/** supported point formats */
|
||||||
TLS_EXT_EC_POINT_FORMATS = 11,
|
TLS_EXT_EC_POINT_FORMATS = 11,
|
||||||
/** list supported signature algorithms */
|
/** list supported signature algorithms */
|
||||||
TLS_EXT_SIGNATURE_ALGORITHMS = 13,
|
TLS_EXT_SIGNATURE_ALGORITHMS = 13,
|
||||||
|
/** indicate usage of Datagram Transport Layer Security (DTLS) */
|
||||||
|
TLS_EXT_USE_SRTP = 14,
|
||||||
|
/** indicate usage of heartbeat */
|
||||||
|
TLS_EXT_HEARTBEAT = 15,
|
||||||
|
/** indicate usage of application-layer protocol negotiation */
|
||||||
|
TLS_EXT_APPLICATION_LAYER_PROTOCOL_NEGOTIATION = 16,
|
||||||
|
/** exchange raw public key, client side*/
|
||||||
|
TLS_CLIENT_CERTIFICATE_TYPE = 19,
|
||||||
|
/** exchange raw public key, server side*/
|
||||||
|
TLS_SERVER_CERTIFICATE_TYPE = 20,
|
||||||
|
/** negotiate identity of the psk **/
|
||||||
|
TLS_EXT_PRE_SHARED_KEY = 41,
|
||||||
|
/** send data in 0-RTT when psk is used and early data is allowed **/
|
||||||
|
TLS_EXT_EARLY_DATA = 42,
|
||||||
|
/** negotiate supported tls versions **/
|
||||||
|
TLS_EXT_SUPPORTED_VERSIONS = 43,
|
||||||
|
/** identify client **/
|
||||||
|
TLS_EXT_COOKIE = 44,
|
||||||
|
/** psk modes supported by the client **/
|
||||||
|
TLS_EXT_PSK_KEY_EXCHANGE_MODES = 45,
|
||||||
|
/** indicate supported ca's by endpoint **/
|
||||||
|
TLS_EXT_CERTIFICATE_AUTHORITIES = 47,
|
||||||
|
/** provide oid/value pairs to match client's certificate **/
|
||||||
|
TLS_EXT_OID_FILTERS = 48,
|
||||||
|
/** willing to perform post-handshake authentication **/
|
||||||
|
TLS_EXT_POST_HANDSHAKE_AUTH = 49,
|
||||||
|
/** list supported signature algorithms to verify certificates **/
|
||||||
|
TLS_EXT_SIGNATURE_ALGORITHMS_CERT = 50,
|
||||||
|
/** list endpoint's cryptographic parameters **/
|
||||||
|
TLS_EXT_KEY_SHARE = 51,
|
||||||
/** cryptographic binding for RFC 5746 renegotiation indication */
|
/** cryptographic binding for RFC 5746 renegotiation indication */
|
||||||
TLS_EXT_RENEGOTIATION_INFO = 65281,
|
TLS_EXT_RENEGOTIATION_INFO = 65281,
|
||||||
};
|
};
|
||||||
|
@ -216,11 +257,18 @@ struct tls_t {
|
||||||
identification_t* (*get_peer_id)(tls_t *this);
|
identification_t* (*get_peer_id)(tls_t *this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the negotiated TLS/SSL version.
|
* Get the maximum and negotiated TLS/SSL version.
|
||||||
*
|
*
|
||||||
* @return negotiated TLS version
|
* @return max and negotiated TLS version
|
||||||
*/
|
*/
|
||||||
tls_version_t (*get_version)(tls_t *this);
|
tls_version_t (*get_version_max)(tls_t *this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the minimum TLS/SSL version.
|
||||||
|
*
|
||||||
|
* @return min TLS version
|
||||||
|
*/
|
||||||
|
tls_version_t (*get_version_min)(tls_t *this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the negotiated TLS/SSL version.
|
* Set the negotiated TLS/SSL version.
|
||||||
|
|
|
@ -63,19 +63,34 @@ ENUM_NEXT(tls_alert_desc_names, TLS_INTERNAL_ERROR, TLS_INTERNAL_ERROR,
|
||||||
TLS_INSUFFICIENT_SECURITY,
|
TLS_INSUFFICIENT_SECURITY,
|
||||||
"internal error",
|
"internal error",
|
||||||
);
|
);
|
||||||
|
ENUM_NEXT(tls_alert_desc_names, TLS_INAPPROPRIATE_FALLBACK,
|
||||||
|
TLS_INAPPROPRIATE_FALLBACK, TLS_INTERNAL_ERROR,
|
||||||
|
"inappropriate fallback",
|
||||||
|
);
|
||||||
ENUM_NEXT(tls_alert_desc_names, TLS_USER_CANCELED, TLS_USER_CANCELED,
|
ENUM_NEXT(tls_alert_desc_names, TLS_USER_CANCELED, TLS_USER_CANCELED,
|
||||||
TLS_INTERNAL_ERROR,
|
TLS_INAPPROPRIATE_FALLBACK,
|
||||||
"user canceled",
|
"user canceled",
|
||||||
);
|
);
|
||||||
ENUM_NEXT(tls_alert_desc_names, TLS_NO_RENEGOTIATION, TLS_NO_RENEGOTIATION,
|
ENUM_NEXT(tls_alert_desc_names, TLS_NO_RENEGOTIATION, TLS_NO_RENEGOTIATION,
|
||||||
TLS_USER_CANCELED,
|
TLS_USER_CANCELED,
|
||||||
"no renegotiation",
|
"no renegotiation",
|
||||||
);
|
);
|
||||||
ENUM_NEXT(tls_alert_desc_names, TLS_UNSUPPORTED_EXTENSION, TLS_UNSUPPORTED_EXTENSION,
|
ENUM_NEXT(tls_alert_desc_names, TLS_MISSING_EXTENSION, TLS_CERTIFICATE_REQUIRED,
|
||||||
TLS_NO_RENEGOTIATION,
|
TLS_NO_RENEGOTIATION,
|
||||||
|
"missing extensions",
|
||||||
"unsupported extension",
|
"unsupported extension",
|
||||||
|
"certificate unobtainable",
|
||||||
|
"recognized name",
|
||||||
|
"bad certificate status response",
|
||||||
|
"bad certificate hash value",
|
||||||
|
"unknown psk identity",
|
||||||
|
"certificate required",
|
||||||
);
|
);
|
||||||
ENUM_END(tls_alert_desc_names, TLS_UNSUPPORTED_EXTENSION);
|
ENUM_NEXT(tls_alert_desc_names, TLS_NO_APPLICATION_PROTOCOL,
|
||||||
|
TLS_NO_APPLICATION_PROTOCOL, TLS_CERTIFICATE_REQUIRED,
|
||||||
|
"no application protocol"
|
||||||
|
);
|
||||||
|
ENUM_END(tls_alert_desc_names, TLS_NO_APPLICATION_PROTOCOL);
|
||||||
|
|
||||||
|
|
||||||
typedef struct private_tls_alert_t private_tls_alert_t;
|
typedef struct private_tls_alert_t private_tls_alert_t;
|
||||||
|
|
|
@ -61,9 +61,18 @@ enum tls_alert_desc_t {
|
||||||
TLS_PROTOCOL_VERSION = 70,
|
TLS_PROTOCOL_VERSION = 70,
|
||||||
TLS_INSUFFICIENT_SECURITY = 71,
|
TLS_INSUFFICIENT_SECURITY = 71,
|
||||||
TLS_INTERNAL_ERROR = 80,
|
TLS_INTERNAL_ERROR = 80,
|
||||||
|
TLS_INAPPROPRIATE_FALLBACK = 86,
|
||||||
TLS_USER_CANCELED = 90,
|
TLS_USER_CANCELED = 90,
|
||||||
TLS_NO_RENEGOTIATION = 100,
|
TLS_NO_RENEGOTIATION = 100,
|
||||||
|
TLS_MISSING_EXTENSION = 109,
|
||||||
TLS_UNSUPPORTED_EXTENSION = 110,
|
TLS_UNSUPPORTED_EXTENSION = 110,
|
||||||
|
TLS_CERTIFICATE_UNOBTAINABLE = 111,
|
||||||
|
TLS_RECOGNIZED_NAME = 112,
|
||||||
|
TLS_BAD_CERTIFICATE_STATUS_RESPONSE = 113,
|
||||||
|
TLS_BAD_CERTIFICATE_HASH_VALUE = 114,
|
||||||
|
TLS_UNKNOWN_PSK_IDENTITY = 115,
|
||||||
|
TLS_CERTIFICATE_REQUIRED = 116,
|
||||||
|
TLS_NO_APPLICATION_PROTOCOL = 120,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tls_crypto.h"
|
#include "tls_crypto.h"
|
||||||
|
#include "tls_hkdf.h"
|
||||||
|
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <plugins/plugin_feature.h>
|
#include <plugins/plugin_feature.h>
|
||||||
|
@ -175,9 +176,17 @@ ENUM_NEXT(tls_cipher_suite_names, TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
||||||
TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
||||||
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256,
|
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
|
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
|
||||||
|
ENUM_NEXT(tls_cipher_suite_names, TLS_AES_128_GCM_SHA256,
|
||||||
|
TLS_AES_128_CCM_8_SHA256,
|
||||||
|
TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_AES_128_CCM_SHA256",
|
||||||
|
"TLS_AES_128_CCM_8_SHA256");
|
||||||
ENUM_NEXT(tls_cipher_suite_names, TLS_ECDH_ECDSA_WITH_NULL_SHA,
|
ENUM_NEXT(tls_cipher_suite_names, TLS_ECDH_ECDSA_WITH_NULL_SHA,
|
||||||
TLS_ECDHE_PSK_WITH_NULL_SHA384,
|
TLS_ECDHE_PSK_WITH_NULL_SHA384,
|
||||||
TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
TLS_AES_128_CCM_8_SHA256,
|
||||||
"TLS_ECDH_ECDSA_WITH_NULL_SHA",
|
"TLS_ECDH_ECDSA_WITH_NULL_SHA",
|
||||||
"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
|
"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
|
||||||
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||||
|
@ -279,7 +288,7 @@ ENUM(tls_ecc_curve_type_names, TLS_ECC_EXPLICIT_PRIME, TLS_ECC_NAMED_CURVE,
|
||||||
"NAMED_CURVE",
|
"NAMED_CURVE",
|
||||||
);
|
);
|
||||||
|
|
||||||
ENUM(tls_named_curve_names, TLS_SECT163K1, TLS_SECP521R1,
|
ENUM_BEGIN(tls_named_group_names, TLS_SECT163K1, TLS_SECP521R1,
|
||||||
"SECT163K1",
|
"SECT163K1",
|
||||||
"SECT163R1",
|
"SECT163R1",
|
||||||
"SECT163R2",
|
"SECT163R2",
|
||||||
|
@ -306,6 +315,18 @@ ENUM(tls_named_curve_names, TLS_SECT163K1, TLS_SECP521R1,
|
||||||
"SECP384R1",
|
"SECP384R1",
|
||||||
"SECP521R1",
|
"SECP521R1",
|
||||||
);
|
);
|
||||||
|
ENUM_NEXT(tls_named_group_names, TLS_CURVE25519, TLS_CURVE_448, TLS_SECP521R1,
|
||||||
|
"CURVE25519",
|
||||||
|
"CURVE448",
|
||||||
|
);
|
||||||
|
ENUM_NEXT(tls_named_group_names, TLS_FFDHE2048, TLS_FFDHE8192, TLS_CURVE_448,
|
||||||
|
"FFDHE2048",
|
||||||
|
"FFDHE3072",
|
||||||
|
"FFDHE4096",
|
||||||
|
"FFDHE6144",
|
||||||
|
"FFDHE8192",
|
||||||
|
);
|
||||||
|
ENUM_END(tls_named_group_names, TLS_FFDHE8192);
|
||||||
|
|
||||||
ENUM(tls_ansi_point_format_names, TLS_ANSI_COMPRESSED, TLS_ANSI_HYBRID_Y,
|
ENUM(tls_ansi_point_format_names, TLS_ANSI_COMPRESSED, TLS_ANSI_HYBRID_Y,
|
||||||
"compressed",
|
"compressed",
|
||||||
|
@ -350,6 +371,11 @@ struct private_tls_crypto_t {
|
||||||
*/
|
*/
|
||||||
int suite_count;
|
int suite_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HKDF for TLS 1.3
|
||||||
|
*/
|
||||||
|
tls_hkdf_t *hkdf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selected cipher suite
|
* Selected cipher suite
|
||||||
*/
|
*/
|
||||||
|
@ -365,6 +391,35 @@ struct private_tls_crypto_t {
|
||||||
*/
|
*/
|
||||||
bool ecdsa;
|
bool ecdsa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MD5 supported?
|
||||||
|
*/
|
||||||
|
bool md5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA1 supported?
|
||||||
|
*/
|
||||||
|
bool sha1;
|
||||||
|
/**
|
||||||
|
* SHA224 supported?
|
||||||
|
*/
|
||||||
|
bool sha224;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SHA256 supported?
|
||||||
|
*/
|
||||||
|
bool sha256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA384 supported?
|
||||||
|
*/
|
||||||
|
bool sha384;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA512 supported?
|
||||||
|
*/
|
||||||
|
bool sha512;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TLS context
|
* TLS context
|
||||||
*/
|
*/
|
||||||
|
@ -415,216 +470,291 @@ typedef struct {
|
||||||
integrity_algorithm_t mac;
|
integrity_algorithm_t mac;
|
||||||
encryption_algorithm_t encr;
|
encryption_algorithm_t encr;
|
||||||
size_t encr_size;
|
size_t encr_size;
|
||||||
|
tls_version_t tls_version;
|
||||||
} suite_algs_t;
|
} suite_algs_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping suites to a set of algorithms
|
* Mapping suites to a set of algorithms
|
||||||
*/
|
*/
|
||||||
static suite_algs_t suite_algs[] = {
|
static suite_algs_t suite_algs[] = {
|
||||||
|
/* Cipher suites of TLS 1.3: key exchange and authentication
|
||||||
|
* delegated to extensions, therefore KEY_ANY, MODP_NONE, PRF_UNDEFINED */
|
||||||
|
{ TLS_AES_128_GCM_SHA256,
|
||||||
|
KEY_ANY, MODP_NONE,
|
||||||
|
HASH_SHA256, PRF_UNDEFINED,
|
||||||
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_GCM_ICV16, 16,
|
||||||
|
TLS_1_3,
|
||||||
|
},
|
||||||
|
{ TLS_AES_256_GCM_SHA384,
|
||||||
|
KEY_ANY, MODP_NONE,
|
||||||
|
HASH_SHA384, PRF_UNDEFINED,
|
||||||
|
AUTH_HMAC_SHA2_384_384, ENCR_AES_GCM_ICV16, 32,
|
||||||
|
TLS_1_3,
|
||||||
|
},
|
||||||
|
{ TLS_CHACHA20_POLY1305_SHA256,
|
||||||
|
KEY_ANY, MODP_NONE,
|
||||||
|
HASH_SHA256, PRF_UNDEFINED,
|
||||||
|
AUTH_HMAC_SHA2_256_256, ENCR_CHACHA20_POLY1305, 16,
|
||||||
|
TLS_1_3,
|
||||||
|
},
|
||||||
|
{ TLS_AES_128_CCM_SHA256,
|
||||||
|
KEY_ANY, MODP_NONE,
|
||||||
|
HASH_SHA256, PRF_UNDEFINED,
|
||||||
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_CCM_ICV16, 16,
|
||||||
|
TLS_1_3,
|
||||||
|
},
|
||||||
|
{ TLS_AES_128_CCM_8_SHA256,
|
||||||
|
KEY_ANY, MODP_NONE,
|
||||||
|
HASH_SHA256, PRF_UNDEFINED,
|
||||||
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_CCM_ICV8, 16,
|
||||||
|
TLS_1_3,
|
||||||
|
},
|
||||||
|
/* Legacy TLS cipher suites */
|
||||||
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||||
KEY_ECDSA, ECP_256_BIT,
|
KEY_ECDSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
|
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||||
KEY_ECDSA, ECP_256_BIT,
|
KEY_ECDSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||||
KEY_ECDSA, ECP_384_BIT,
|
KEY_ECDSA, ECP_384_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
|
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||||
KEY_ECDSA, ECP_384_BIT,
|
KEY_ECDSA, ECP_384_BIT,
|
||||||
HASH_SHA384, PRF_HMAC_SHA2_384,
|
HASH_SHA384, PRF_HMAC_SHA2_384,
|
||||||
AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32
|
AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
{ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
KEY_ECDSA, ECP_256_BIT,
|
KEY_ECDSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
|
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
{ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
KEY_ECDSA, ECP_384_BIT,
|
KEY_ECDSA, ECP_384_BIT,
|
||||||
HASH_SHA384, PRF_HMAC_SHA2_384,
|
HASH_SHA384, PRF_HMAC_SHA2_384,
|
||||||
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
|
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||||
KEY_RSA, ECP_256_BIT,
|
KEY_RSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
|
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
KEY_RSA, ECP_256_BIT,
|
KEY_RSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||||
KEY_RSA, ECP_384_BIT,
|
KEY_RSA, ECP_384_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
|
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
||||||
KEY_RSA, ECP_384_BIT,
|
KEY_RSA, ECP_384_BIT,
|
||||||
HASH_SHA384, PRF_HMAC_SHA2_384,
|
HASH_SHA384, PRF_HMAC_SHA2_384,
|
||||||
AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32
|
AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
{ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
KEY_RSA, ECP_256_BIT,
|
KEY_RSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
|
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
KEY_RSA, ECP_384_BIT,
|
KEY_RSA, ECP_384_BIT,
|
||||||
HASH_SHA384, PRF_HMAC_SHA2_384,
|
HASH_SHA384, PRF_HMAC_SHA2_384,
|
||||||
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
|
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
|
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
|
||||||
KEY_RSA, MODP_2048_BIT,
|
KEY_RSA, MODP_2048_BIT,
|
||||||
HASH_SHA256,PRF_HMAC_SHA2_256,
|
HASH_SHA256,PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
|
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
|
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
KEY_RSA, MODP_3072_BIT,
|
KEY_RSA, MODP_3072_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
||||||
KEY_RSA, MODP_3072_BIT,
|
KEY_RSA, MODP_3072_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
|
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
|
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
|
||||||
KEY_RSA, MODP_4096_BIT,
|
KEY_RSA, MODP_4096_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
|
{ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
KEY_RSA, MODP_3072_BIT,
|
KEY_RSA, MODP_3072_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
|
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
|
{ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
KEY_RSA, MODP_4096_BIT,
|
KEY_RSA, MODP_4096_BIT,
|
||||||
HASH_SHA384, PRF_HMAC_SHA2_384,
|
HASH_SHA384, PRF_HMAC_SHA2_384,
|
||||||
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
|
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
||||||
KEY_RSA, MODP_2048_BIT,
|
KEY_RSA, MODP_2048_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16
|
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
KEY_RSA, MODP_3072_BIT,
|
KEY_RSA, MODP_3072_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 16
|
AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
||||||
KEY_RSA, MODP_3072_BIT,
|
KEY_RSA, MODP_3072_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32
|
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
KEY_RSA, MODP_4096_BIT,
|
KEY_RSA, MODP_4096_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 32
|
AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
KEY_RSA, MODP_2048_BIT,
|
KEY_RSA, MODP_2048_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
|
AUTH_HMAC_SHA1_160, ENCR_3DES, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_AES_128_CBC_SHA,
|
{ TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
|
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_AES_128_CBC_SHA256,
|
{ TLS_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_AES_256_CBC_SHA,
|
{ TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
|
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_AES_256_CBC_SHA256,
|
{ TLS_RSA_WITH_AES_256_CBC_SHA256,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32
|
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_AES_128_GCM_SHA256,
|
{ TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
|
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_AES_256_GCM_SHA384,
|
{ TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA384, PRF_HMAC_SHA2_384,
|
HASH_SHA384, PRF_HMAC_SHA2_384,
|
||||||
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
|
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16
|
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 16
|
AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 16,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32
|
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 32
|
AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 32,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
{ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
KEY_ECDSA, ECP_256_BIT,
|
KEY_ECDSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
|
AUTH_HMAC_SHA1_160, ENCR_3DES, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
{ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
KEY_RSA, ECP_256_BIT,
|
KEY_RSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
|
AUTH_HMAC_SHA1_160, ENCR_3DES, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
|
AUTH_HMAC_SHA1_160, ENCR_3DES, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_ECDSA_WITH_NULL_SHA,
|
{ TLS_ECDHE_ECDSA_WITH_NULL_SHA,
|
||||||
KEY_ECDSA, ECP_256_BIT,
|
KEY_ECDSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
|
AUTH_HMAC_SHA1_160, ENCR_NULL, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_ECDHE_RSA_WITH_NULL_SHA,
|
{ TLS_ECDHE_RSA_WITH_NULL_SHA,
|
||||||
KEY_ECDSA, ECP_256_BIT,
|
KEY_ECDSA, ECP_256_BIT,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
|
AUTH_HMAC_SHA1_160, ENCR_NULL, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_NULL_SHA,
|
{ TLS_RSA_WITH_NULL_SHA,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
|
AUTH_HMAC_SHA1_160, ENCR_NULL, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_NULL_SHA256,
|
{ TLS_RSA_WITH_NULL_SHA256,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_SHA2_256_256, ENCR_NULL, 0
|
AUTH_HMAC_SHA2_256_256, ENCR_NULL, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
{ TLS_RSA_WITH_NULL_MD5,
|
{ TLS_RSA_WITH_NULL_MD5,
|
||||||
KEY_RSA, MODP_NONE,
|
KEY_RSA, MODP_NONE,
|
||||||
HASH_SHA256, PRF_HMAC_SHA2_256,
|
HASH_SHA256, PRF_HMAC_SHA2_256,
|
||||||
AUTH_HMAC_MD5_128, ENCR_NULL, 0
|
AUTH_HMAC_MD5_128, ENCR_NULL, 0,
|
||||||
|
TLS_1_2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -978,14 +1108,17 @@ static void filter_specific_config_suites(private_tls_crypto_t *this,
|
||||||
static void filter_unsupported_suites(suite_algs_t suites[], int *count)
|
static void filter_unsupported_suites(suite_algs_t suites[], int *count)
|
||||||
{
|
{
|
||||||
/* filter suite list by each algorithm */
|
/* filter suite list by each algorithm */
|
||||||
|
if (suites->tls_version < TLS_1_3)
|
||||||
|
{
|
||||||
|
filter_suite(suites, count, offsetof(suite_algs_t, encr),
|
||||||
|
lib->crypto->create_aead_enumerator);
|
||||||
|
filter_suite(suites, count, offsetof(suite_algs_t, prf),
|
||||||
|
lib->crypto->create_prf_enumerator);
|
||||||
|
}
|
||||||
filter_suite(suites, count, offsetof(suite_algs_t, encr),
|
filter_suite(suites, count, offsetof(suite_algs_t, encr),
|
||||||
lib->crypto->create_crypter_enumerator);
|
lib->crypto->create_crypter_enumerator);
|
||||||
filter_suite(suites, count, offsetof(suite_algs_t, encr),
|
|
||||||
lib->crypto->create_aead_enumerator);
|
|
||||||
filter_suite(suites, count, offsetof(suite_algs_t, mac),
|
filter_suite(suites, count, offsetof(suite_algs_t, mac),
|
||||||
lib->crypto->create_signer_enumerator);
|
lib->crypto->create_signer_enumerator);
|
||||||
filter_suite(suites, count, offsetof(suite_algs_t, prf),
|
|
||||||
lib->crypto->create_prf_enumerator);
|
|
||||||
filter_suite(suites, count, offsetof(suite_algs_t, hash),
|
filter_suite(suites, count, offsetof(suite_algs_t, hash),
|
||||||
lib->crypto->create_hasher_enumerator);
|
lib->crypto->create_hasher_enumerator);
|
||||||
filter_suite(suites, count, offsetof(suite_algs_t, dh),
|
filter_suite(suites, count, offsetof(suite_algs_t, dh),
|
||||||
|
@ -1068,7 +1201,7 @@ static bool create_null(private_tls_crypto_t *this, suite_algs_t *algs)
|
||||||
*/
|
*/
|
||||||
static bool create_traditional(private_tls_crypto_t *this, suite_algs_t *algs)
|
static bool create_traditional(private_tls_crypto_t *this, suite_algs_t *algs)
|
||||||
{
|
{
|
||||||
if (this->tls->get_version(this->tls) < TLS_1_1)
|
if (this->tls->get_version_max(this->tls) < TLS_1_1)
|
||||||
{
|
{
|
||||||
this->aead_in = tls_aead_create_implicit(algs->mac,
|
this->aead_in = tls_aead_create_implicit(algs->mac,
|
||||||
algs->encr, algs->encr_size);
|
algs->encr, algs->encr_size);
|
||||||
|
@ -1097,8 +1230,20 @@ static bool create_traditional(private_tls_crypto_t *this, suite_algs_t *algs)
|
||||||
*/
|
*/
|
||||||
static bool create_aead(private_tls_crypto_t *this, suite_algs_t *algs)
|
static bool create_aead(private_tls_crypto_t *this, suite_algs_t *algs)
|
||||||
{
|
{
|
||||||
this->aead_in = tls_aead_create_aead(algs->encr, algs->encr_size);
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
this->aead_out = tls_aead_create_aead(algs->encr, algs->encr_size);
|
{
|
||||||
|
this->aead_in = tls_aead_create_aead(algs->encr, algs->encr_size);
|
||||||
|
this->aead_out = tls_aead_create_aead(algs->encr, algs->encr_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->aead_in = tls_aead_create_seq(algs->encr, algs->encr_size);
|
||||||
|
this->aead_out = tls_aead_create_seq(algs->encr, algs->encr_size);
|
||||||
|
|
||||||
|
this->protection->set_cipher(this->protection, TRUE, this->aead_in);
|
||||||
|
this->protection->set_cipher(this->protection, FALSE, this->aead_out);
|
||||||
|
|
||||||
|
}
|
||||||
if (!this->aead_in || !this->aead_out)
|
if (!this->aead_in || !this->aead_out)
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "selected TLS transforms %N-%u not supported",
|
DBG1(DBG_TLS, "selected TLS transforms %N-%u not supported",
|
||||||
|
@ -1125,18 +1270,30 @@ static bool create_ciphers(private_tls_crypto_t *this, suite_algs_t *algs)
|
||||||
{
|
{
|
||||||
destroy_aeads(this);
|
destroy_aeads(this);
|
||||||
DESTROY_IF(this->prf);
|
DESTROY_IF(this->prf);
|
||||||
if (this->tls->get_version(this->tls) < TLS_1_2)
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
{
|
{
|
||||||
this->prf = tls_prf_create_10();
|
if (this->tls->get_version_max(this->tls) < TLS_1_2)
|
||||||
|
{
|
||||||
|
this->prf = tls_prf_create_10();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->prf = tls_prf_create_12(algs->prf);
|
||||||
|
}
|
||||||
|
if (!this->prf)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "selected TLS PRF not supported");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->prf = tls_prf_create_12(algs->prf);
|
this->hkdf = tls_hkdf_create(algs->hash, chunk_empty);
|
||||||
}
|
if (!this->hkdf)
|
||||||
if (!this->prf)
|
{
|
||||||
{
|
DBG1(DBG_TLS, "TLS HKDF creation unsuccessful");
|
||||||
DBG1(DBG_TLS, "selected TLS PRF not supported");
|
return FALSE;
|
||||||
return FALSE;
|
}
|
||||||
}
|
}
|
||||||
if (algs->encr == ENCR_NULL)
|
if (algs->encr == ENCR_NULL)
|
||||||
{
|
{
|
||||||
|
@ -1245,6 +1402,30 @@ METHOD(tls_crypto_t, get_signature_algorithms, void,
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (schemes[i].hash == TLS_HASH_MD5 && !this->md5)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (schemes[i].hash == TLS_HASH_SHA1 && !this->sha1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (schemes[i].hash == TLS_HASH_SHA224 && !this->sha224)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (schemes[i].hash == TLS_HASH_SHA256 && !this->sha256)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (schemes[i].hash == TLS_HASH_SHA384 && !this->sha384)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (schemes[i].hash == TLS_HASH_SHA512 && !this->sha512)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!lib->plugins->has_feature(lib->plugins,
|
if (!lib->plugins->has_feature(lib->plugins,
|
||||||
PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[i].scheme)))
|
PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[i].scheme)))
|
||||||
{
|
{
|
||||||
|
@ -1287,7 +1468,7 @@ static signature_scheme_t hashsig_to_scheme(key_type_t type,
|
||||||
*/
|
*/
|
||||||
static struct {
|
static struct {
|
||||||
diffie_hellman_group_t group;
|
diffie_hellman_group_t group;
|
||||||
tls_named_curve_t curve;
|
tls_named_group_t curve;
|
||||||
} curves[] = {
|
} curves[] = {
|
||||||
{ ECP_256_BIT, TLS_SECP256R1},
|
{ ECP_256_BIT, TLS_SECP256R1},
|
||||||
{ ECP_384_BIT, TLS_SECP384R1},
|
{ ECP_384_BIT, TLS_SECP384R1},
|
||||||
|
@ -1300,7 +1481,7 @@ CALLBACK(group_filter, bool,
|
||||||
void *null, enumerator_t *orig, va_list args)
|
void *null, enumerator_t *orig, va_list args)
|
||||||
{
|
{
|
||||||
diffie_hellman_group_t group, *out;
|
diffie_hellman_group_t group, *out;
|
||||||
tls_named_curve_t *curve;
|
tls_named_group_t *curve;
|
||||||
char *plugin;
|
char *plugin;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -1357,7 +1538,7 @@ METHOD(tls_crypto_t, append_handshake, void,
|
||||||
*/
|
*/
|
||||||
static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash)
|
static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash)
|
||||||
{
|
{
|
||||||
if (this->tls->get_version(this->tls) >= TLS_1_2)
|
if (this->tls->get_version_max(this->tls) >= TLS_1_2)
|
||||||
{
|
{
|
||||||
hasher_t *hasher;
|
hasher_t *hasher;
|
||||||
suite_algs_t *alg;
|
suite_algs_t *alg;
|
||||||
|
@ -1407,7 +1588,7 @@ METHOD(tls_crypto_t, sign, bool,
|
||||||
private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer,
|
private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer,
|
||||||
chunk_t data, chunk_t hashsig)
|
chunk_t data, chunk_t hashsig)
|
||||||
{
|
{
|
||||||
if (this->tls->get_version(this->tls) >= TLS_1_2)
|
if (this->tls->get_version_max(this->tls) >= TLS_1_2)
|
||||||
{
|
{
|
||||||
const chunk_t hashsig_def = chunk_from_chars(
|
const chunk_t hashsig_def = chunk_from_chars(
|
||||||
TLS_HASH_SHA1, TLS_SIG_RSA, TLS_HASH_SHA1, TLS_SIG_ECDSA);
|
TLS_HASH_SHA1, TLS_SIG_RSA, TLS_HASH_SHA1, TLS_SIG_ECDSA);
|
||||||
|
@ -1490,7 +1671,64 @@ METHOD(tls_crypto_t, verify, bool,
|
||||||
private_tls_crypto_t *this, public_key_t *key, bio_reader_t *reader,
|
private_tls_crypto_t *this, public_key_t *key, bio_reader_t *reader,
|
||||||
chunk_t data)
|
chunk_t data)
|
||||||
{
|
{
|
||||||
if (this->tls->get_version(this->tls) >= TLS_1_2)
|
if (this->tls->get_version_max(this->tls) == TLS_1_3)
|
||||||
|
{
|
||||||
|
signature_scheme_t scheme = SIGN_UNKNOWN;
|
||||||
|
uint8_t hash, alg;
|
||||||
|
chunk_t sig, transcript_hash, static_sig_data_all;
|
||||||
|
|
||||||
|
chunk_t static_sig_data = chunk_from_chars(
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x54, 0x4c, 0x53, 0x20, 0x31, 0x2e, 0x33, 0x2c,
|
||||||
|
0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
|
||||||
|
0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||||
|
0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66,
|
||||||
|
0x79, 0x00,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!reader->read_uint8(reader, &hash) ||
|
||||||
|
!reader->read_uint8(reader, &alg) ||
|
||||||
|
!reader->read_data16(reader, &sig))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "received invalid signature");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hash_data(this, data, &transcript_hash))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "Unable to hash");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_sig_data_all = chunk_cat("cc", static_sig_data, transcript_hash);
|
||||||
|
scheme = hashsig_to_scheme(key->get_type(key), hash, alg);
|
||||||
|
if (scheme == SIGN_UNKNOWN)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "signature algorithms %N/%N not supported",
|
||||||
|
tls_hash_algorithm_names, hash,
|
||||||
|
tls_signature_algorithm_names, alg);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!key->verify(key, scheme, NULL, static_sig_data_all, sig))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "verification of signature failed");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
DBG2(DBG_TLS,
|
||||||
|
"verified signature with %N/%N",
|
||||||
|
tls_hash_algorithm_names,
|
||||||
|
hash,
|
||||||
|
tls_signature_algorithm_names,
|
||||||
|
alg);
|
||||||
|
}
|
||||||
|
else if (this->tls->get_version_max(this->tls) == TLS_1_2)
|
||||||
{
|
{
|
||||||
signature_scheme_t scheme = SIGN_UNKNOWN;
|
signature_scheme_t scheme = SIGN_UNKNOWN;
|
||||||
uint8_t hash, alg;
|
uint8_t hash, alg;
|
||||||
|
@ -1594,6 +1832,42 @@ METHOD(tls_crypto_t, calculate_finished, bool,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(tls_crypto_t, calculate_finished_tls13, bool,
|
||||||
|
private_tls_crypto_t *this, bool is_server, chunk_t *out)
|
||||||
|
{
|
||||||
|
chunk_t finished_key, finished_hash;
|
||||||
|
prf_t *prf;
|
||||||
|
|
||||||
|
this->hkdf->derive_finished(this->hkdf, is_server, &finished_key);
|
||||||
|
if (!hash_data(this, this->handshake, &finished_hash))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "creating hash of handshake failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->suite == TLS_AES_256_GCM_SHA384)
|
||||||
|
{
|
||||||
|
prf = lib->crypto->create_prf(lib->crypto, PRF_HMAC_SHA2_384);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prf = lib->crypto->create_prf(lib->crypto, PRF_HMAC_SHA2_256);
|
||||||
|
}
|
||||||
|
if(!prf->set_key(prf, finished_key) ||
|
||||||
|
!prf->allocate_bytes(prf, finished_hash, out))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "setting key or generating hash for HMAC failed");
|
||||||
|
chunk_clear(&finished_key);
|
||||||
|
chunk_clear(&finished_hash);
|
||||||
|
prf->destroy(prf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_clear(&finished_key);
|
||||||
|
chunk_clear(&finished_hash);
|
||||||
|
prf->destroy(prf);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derive master secret from premaster, optionally save session
|
* Derive master secret from premaster, optionally save session
|
||||||
*/
|
*/
|
||||||
|
@ -1710,6 +1984,150 @@ METHOD(tls_crypto_t, derive_secrets, bool,
|
||||||
expand_keys(this, client_random, server_random);
|
expand_keys(this, client_random, server_random);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(tls_crypto_t, derive_handshake_secret, bool,
|
||||||
|
private_tls_crypto_t *this, chunk_t shared_secret)
|
||||||
|
{
|
||||||
|
chunk_t c_key, c_iv, s_key, s_iv;
|
||||||
|
|
||||||
|
this->hkdf->set_shared_secret(this->hkdf, shared_secret);
|
||||||
|
|
||||||
|
/* client key material */
|
||||||
|
if (!this->hkdf->generate_secret(this->hkdf, TLS_HKDF_C_HS_TRAFFIC,
|
||||||
|
this->handshake, NULL) ||
|
||||||
|
!this->hkdf->derive_key(this->hkdf, FALSE,
|
||||||
|
this->aead_out->
|
||||||
|
get_encr_key_size(this->aead_out), &c_key) ||
|
||||||
|
!this->hkdf->derive_iv(this->hkdf, FALSE,
|
||||||
|
this->aead_out->
|
||||||
|
get_iv_size(this->aead_out), &c_iv))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "deriving client key material failed");
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* server key material */
|
||||||
|
if (!this->hkdf->generate_secret(this->hkdf, TLS_HKDF_S_HS_TRAFFIC,
|
||||||
|
this->handshake, NULL) ||
|
||||||
|
!this->hkdf->derive_key(this->hkdf, TRUE, this->aead_in->
|
||||||
|
get_encr_key_size(this->aead_in), &s_key) ||
|
||||||
|
!this->hkdf->derive_iv(this->hkdf, TRUE, this->aead_in->
|
||||||
|
get_iv_size(this->aead_in), &s_iv))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "deriving server key material failed");
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
chunk_clear(&s_key);
|
||||||
|
chunk_clear(&s_iv);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->tls->is_server(this->tls))
|
||||||
|
{
|
||||||
|
if (!this->aead_in->set_keys(this->aead_in, chunk_empty, s_key, s_iv) ||
|
||||||
|
!this->aead_out->set_keys(this->aead_out, chunk_empty, c_key, c_iv))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "setting aead server key material failed");
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
chunk_clear(&s_key);
|
||||||
|
chunk_clear(&s_iv);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!this->aead_in->set_keys(this->aead_in, chunk_empty, s_key, s_iv) ||
|
||||||
|
!this->aead_out->set_keys(this->aead_out, chunk_empty, c_key, c_iv))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "setting aead client key material failed");
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
chunk_clear(&s_key);
|
||||||
|
chunk_clear(&s_iv);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
chunk_clear(&s_key);
|
||||||
|
chunk_clear(&s_iv);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tls_crypto_t, derive_app_secret, bool,
|
||||||
|
private_tls_crypto_t *this)
|
||||||
|
{
|
||||||
|
chunk_t c_key, c_iv, s_key, s_iv;
|
||||||
|
|
||||||
|
/* client key material */
|
||||||
|
if (!this->hkdf->generate_secret(this->hkdf, TLS_HKDF_C_AP_TRAFFIC,
|
||||||
|
this->handshake, NULL) ||
|
||||||
|
!this->hkdf->derive_key(this->hkdf, FALSE,
|
||||||
|
this->aead_out->
|
||||||
|
get_encr_key_size(this->aead_out), &c_key) ||
|
||||||
|
!this->hkdf->derive_iv(this->hkdf, FALSE,
|
||||||
|
this->aead_out->
|
||||||
|
get_iv_size(this->aead_out), &c_iv))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "deriving client key material failed");
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* server key material */
|
||||||
|
if (!this->hkdf->generate_secret(this->hkdf, TLS_HKDF_S_AP_TRAFFIC,
|
||||||
|
this->handshake, NULL) ||
|
||||||
|
!this->hkdf->derive_key(this->hkdf, TRUE, this->aead_in->
|
||||||
|
get_encr_key_size(this->aead_in), &s_key) ||
|
||||||
|
!this->hkdf->derive_iv(this->hkdf, TRUE, this->aead_in->
|
||||||
|
get_iv_size(this->aead_in), &s_iv))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "deriving server key material failed");
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
chunk_clear(&s_key);
|
||||||
|
chunk_clear(&s_iv);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->tls->is_server(this->tls))
|
||||||
|
{
|
||||||
|
if (!this->aead_in->set_keys(this->aead_in, chunk_empty, s_key, s_iv) ||
|
||||||
|
!this->aead_out->set_keys(this->aead_out, chunk_empty, c_key, c_iv))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "setting aead server key material failed");
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
chunk_clear(&s_key);
|
||||||
|
chunk_clear(&s_iv);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!this->aead_in->set_keys(this->aead_in, chunk_empty, s_key, s_iv) ||
|
||||||
|
!this->aead_out->set_keys(this->aead_out, chunk_empty, c_key, c_iv))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "setting aead client key material failed");
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
chunk_clear(&s_key);
|
||||||
|
chunk_clear(&s_iv);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_clear(&c_key);
|
||||||
|
chunk_clear(&c_iv);
|
||||||
|
chunk_clear(&s_key);
|
||||||
|
chunk_clear(&s_iv);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t,
|
METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t,
|
||||||
private_tls_crypto_t *this, chunk_t session, identification_t *id,
|
private_tls_crypto_t *this, chunk_t session, identification_t *id,
|
||||||
chunk_t client_random, chunk_t server_random)
|
chunk_t client_random, chunk_t server_random)
|
||||||
|
@ -1776,6 +2194,7 @@ METHOD(tls_crypto_t, destroy, void,
|
||||||
free(this->handshake.ptr);
|
free(this->handshake.ptr);
|
||||||
free(this->msk.ptr);
|
free(this->msk.ptr);
|
||||||
DESTROY_IF(this->prf);
|
DESTROY_IF(this->prf);
|
||||||
|
DESTROY_IF(this->hkdf);
|
||||||
free(this->suites);
|
free(this->suites);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
@ -1789,6 +2208,8 @@ tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache)
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
credential_type_t type;
|
credential_type_t type;
|
||||||
int subtype;
|
int subtype;
|
||||||
|
int hash_algorithm;
|
||||||
|
const char *plugin;
|
||||||
|
|
||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.public = {
|
||||||
|
@ -1804,7 +2225,10 @@ tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache)
|
||||||
.sign_handshake = _sign_handshake,
|
.sign_handshake = _sign_handshake,
|
||||||
.verify_handshake = _verify_handshake,
|
.verify_handshake = _verify_handshake,
|
||||||
.calculate_finished = _calculate_finished,
|
.calculate_finished = _calculate_finished,
|
||||||
|
.calculate_finished_tls13 = _calculate_finished_tls13,
|
||||||
.derive_secrets = _derive_secrets,
|
.derive_secrets = _derive_secrets,
|
||||||
|
.derive_handshake_secret = _derive_handshake_secret,
|
||||||
|
.derive_app_secret = _derive_app_secret,
|
||||||
.resume_session = _resume_session,
|
.resume_session = _resume_session,
|
||||||
.get_session = _get_session,
|
.get_session = _get_session,
|
||||||
.change_cipher = _change_cipher,
|
.change_cipher = _change_cipher,
|
||||||
|
@ -1835,6 +2259,49 @@ tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache)
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
|
||||||
|
while (enumerator->enumerate(enumerator, &hash_algorithm, &plugin))
|
||||||
|
{
|
||||||
|
switch (hash_algorithm)
|
||||||
|
{
|
||||||
|
case TLS_HASH_MD5:
|
||||||
|
if (tls->get_version_max(tls) < TLS_1_3)
|
||||||
|
{
|
||||||
|
this->md5 = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->md5 = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TLS_HASH_SHA1:
|
||||||
|
this->sha1 = TRUE;
|
||||||
|
break;
|
||||||
|
case TLS_HASH_SHA224:
|
||||||
|
if (tls->get_version_max(tls) < TLS_1_3)
|
||||||
|
{
|
||||||
|
this->sha224 = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->sha224 = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TLS_HASH_SHA384:
|
||||||
|
this->sha384 = TRUE;
|
||||||
|
break;
|
||||||
|
case TLS_HASH_SHA256:
|
||||||
|
this->sha256 = TRUE;
|
||||||
|
break;
|
||||||
|
case TLS_HASH_SHA512:
|
||||||
|
this->sha512 = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
switch (tls->get_purpose(tls))
|
switch (tls->get_purpose(tls))
|
||||||
{
|
{
|
||||||
case TLS_PURPOSE_EAP_TLS:
|
case TLS_PURPOSE_EAP_TLS:
|
||||||
|
|
|
@ -27,7 +27,7 @@ typedef enum tls_hash_algorithm_t tls_hash_algorithm_t;
|
||||||
typedef enum tls_signature_algorithm_t tls_signature_algorithm_t;
|
typedef enum tls_signature_algorithm_t tls_signature_algorithm_t;
|
||||||
typedef enum tls_client_certificate_type_t tls_client_certificate_type_t;
|
typedef enum tls_client_certificate_type_t tls_client_certificate_type_t;
|
||||||
typedef enum tls_ecc_curve_type_t tls_ecc_curve_type_t;
|
typedef enum tls_ecc_curve_type_t tls_ecc_curve_type_t;
|
||||||
typedef enum tls_named_curve_t tls_named_curve_t;
|
typedef enum tls_named_group_t tls_named_group_t;
|
||||||
typedef enum tls_ansi_point_format_t tls_ansi_point_format_t;
|
typedef enum tls_ansi_point_format_t tls_ansi_point_format_t;
|
||||||
typedef enum tls_ec_point_format_t tls_ec_point_format_t;
|
typedef enum tls_ec_point_format_t tls_ec_point_format_t;
|
||||||
|
|
||||||
|
@ -191,6 +191,12 @@ enum tls_cipher_suite_t {
|
||||||
|
|
||||||
TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF,
|
TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF,
|
||||||
|
|
||||||
|
TLS_AES_128_GCM_SHA256 = 0x1301,
|
||||||
|
TLS_AES_256_GCM_SHA384 = 0x1302,
|
||||||
|
TLS_CHACHA20_POLY1305_SHA256 = 0x1303,
|
||||||
|
TLS_AES_128_CCM_SHA256 = 0x1304,
|
||||||
|
TLS_AES_128_CCM_8_SHA256 = 0x1305,
|
||||||
|
|
||||||
TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001,
|
TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001,
|
||||||
TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002,
|
TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002,
|
||||||
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003,
|
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003,
|
||||||
|
@ -327,7 +333,7 @@ extern enum_name_t *tls_ecc_curve_type_names;
|
||||||
/**
|
/**
|
||||||
* TLS Named Curve identifiers
|
* TLS Named Curve identifiers
|
||||||
*/
|
*/
|
||||||
enum tls_named_curve_t {
|
enum tls_named_group_t {
|
||||||
TLS_SECT163K1 = 1,
|
TLS_SECT163K1 = 1,
|
||||||
TLS_SECT163R1 = 2,
|
TLS_SECT163R1 = 2,
|
||||||
TLS_SECT163R2 = 3,
|
TLS_SECT163R2 = 3,
|
||||||
|
@ -353,12 +359,21 @@ enum tls_named_curve_t {
|
||||||
TLS_SECP256R1 = 23,
|
TLS_SECP256R1 = 23,
|
||||||
TLS_SECP384R1 = 24,
|
TLS_SECP384R1 = 24,
|
||||||
TLS_SECP521R1 = 25,
|
TLS_SECP521R1 = 25,
|
||||||
|
|
||||||
|
/* TLS 1.3: new ecdhe, dhe groups */
|
||||||
|
TLS_CURVE25519 = 29,
|
||||||
|
TLS_CURVE_448 = 30,
|
||||||
|
TLS_FFDHE2048 = 256,
|
||||||
|
TLS_FFDHE3072 = 257,
|
||||||
|
TLS_FFDHE4096 = 258,
|
||||||
|
TLS_FFDHE6144 = 259,
|
||||||
|
TLS_FFDHE8192 = 260,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum names for tls_named_curve_t
|
* Enum names for tls_named_group_t
|
||||||
*/
|
*/
|
||||||
extern enum_name_t *tls_named_curve_names;
|
extern enum_name_t *tls_named_group_names;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EC Point format, ANSI X9.62.
|
* EC Point format, ANSI X9.62.
|
||||||
|
@ -432,7 +447,7 @@ struct tls_crypto_t {
|
||||||
/**
|
/**
|
||||||
* Create an enumerator over supported ECDH groups.
|
* Create an enumerator over supported ECDH groups.
|
||||||
*
|
*
|
||||||
* Enumerates over (diffie_hellman_group_t, tls_named_curve_t)
|
* Enumerates over (diffie_hellman_group_t, tls_named_group_t)
|
||||||
*
|
*
|
||||||
* @return enumerator
|
* @return enumerator
|
||||||
*/
|
*/
|
||||||
|
@ -499,7 +514,7 @@ struct tls_crypto_t {
|
||||||
bio_reader_t *reader);
|
bio_reader_t *reader);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the data of a TLS finished message.
|
* Calculate the data of a legacyTLS finished message.
|
||||||
*
|
*
|
||||||
* @param label ASCII label to use for calculation
|
* @param label ASCII label to use for calculation
|
||||||
* @param out buffer to write finished data to
|
* @param out buffer to write finished data to
|
||||||
|
@ -507,6 +522,15 @@ struct tls_crypto_t {
|
||||||
*/
|
*/
|
||||||
bool (*calculate_finished)(tls_crypto_t *this, char *label, char out[12]);
|
bool (*calculate_finished)(tls_crypto_t *this, char *label, char out[12]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the data of a TLS finished message.
|
||||||
|
*
|
||||||
|
* @param out buffer to write finished data to
|
||||||
|
* @return TRUE if calculation successful
|
||||||
|
*/
|
||||||
|
bool (*calculate_finished_tls13)(tls_crypto_t *this, bool is_server,
|
||||||
|
chunk_t *out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derive the master secret, MAC and encryption keys.
|
* Derive the master secret, MAC and encryption keys.
|
||||||
*
|
*
|
||||||
|
@ -521,6 +545,21 @@ struct tls_crypto_t {
|
||||||
chunk_t session, identification_t *id,
|
chunk_t session, identification_t *id,
|
||||||
chunk_t client_random, chunk_t server_random);
|
chunk_t client_random, chunk_t server_random);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive the handshake keys.
|
||||||
|
*
|
||||||
|
* @param shared_secret input key material
|
||||||
|
* @return TRUE if secret derived successfully
|
||||||
|
*/
|
||||||
|
bool (*derive_handshake_secret)(tls_crypto_t *this, chunk_t shared_secret);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive the application keys.
|
||||||
|
*
|
||||||
|
* @return TRUE if secret derived successfully
|
||||||
|
*/
|
||||||
|
bool (*derive_app_secret)(tls_crypto_t *this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to resume a TLS session, derive key material.
|
* Try to resume a TLS session, derive key material.
|
||||||
*
|
*
|
||||||
|
|
|
@ -292,7 +292,11 @@ METHOD(tls_fragmentation_t, process, status_t,
|
||||||
break;
|
break;
|
||||||
case TLS_HANDSHAKE:
|
case TLS_HANDSHAKE:
|
||||||
status = process_handshake(this, reader);
|
status = process_handshake(this, reader);
|
||||||
break;
|
if (!this->handshake->finished(this->handshake))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall */
|
||||||
case TLS_APPLICATION_DATA:
|
case TLS_APPLICATION_DATA:
|
||||||
status = process_application(this, reader);
|
status = process_application(this, reader);
|
||||||
break;
|
break;
|
||||||
|
@ -353,7 +357,8 @@ static status_t build_handshake(private_tls_fragmentation_t *this)
|
||||||
msg->write_data24(msg, hs->get_buf(hs));
|
msg->write_data24(msg, hs->get_buf(hs));
|
||||||
DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)",
|
DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)",
|
||||||
tls_handshake_type_names, type, hs->get_buf(hs).len);
|
tls_handshake_type_names, type, hs->get_buf(hs).len);
|
||||||
if (!this->handshake->cipherspec_changed(this->handshake, FALSE))
|
if (type != TLS_FINISHED &&
|
||||||
|
!this->handshake->cipherspec_changed(this->handshake, FALSE))
|
||||||
{
|
{
|
||||||
hs->destroy(hs);
|
hs->destroy(hs);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -37,6 +37,12 @@ typedef enum {
|
||||||
STATE_FINISHED_SENT,
|
STATE_FINISHED_SENT,
|
||||||
STATE_CIPHERSPEC_CHANGED_IN,
|
STATE_CIPHERSPEC_CHANGED_IN,
|
||||||
STATE_FINISHED_RECEIVED,
|
STATE_FINISHED_RECEIVED,
|
||||||
|
/* new states in TLS 1.3 */
|
||||||
|
STATE_HELLORETRYREQ_RECEIVED,
|
||||||
|
STATE_ENCRYPTED_EXTENSIONS_RECEIVED,
|
||||||
|
STATE_CERT_VERIFY_RECEIVED,
|
||||||
|
STATE_FINISHED_SENT_KEY_SWITCHED,
|
||||||
|
|
||||||
} peer_state_t;
|
} peer_state_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,8 +149,11 @@ static status_t process_server_hello(private_tls_peer_t *this,
|
||||||
{
|
{
|
||||||
uint8_t compression;
|
uint8_t compression;
|
||||||
uint16_t version, cipher;
|
uint16_t version, cipher;
|
||||||
chunk_t random, session, ext = chunk_empty;
|
chunk_t random, session, ext = chunk_empty, ext_key_share = chunk_empty;
|
||||||
tls_cipher_suite_t suite = 0;
|
tls_cipher_suite_t suite = 0;
|
||||||
|
int offset = 0;
|
||||||
|
uint16_t extension_type, extension_length;
|
||||||
|
uint16_t key_type, key_length;
|
||||||
|
|
||||||
this->crypto->append_handshake(this->crypto,
|
this->crypto->append_handshake(this->crypto,
|
||||||
TLS_SERVER_HELLO, reader->peek(reader));
|
TLS_SERVER_HELLO, reader->peek(reader));
|
||||||
|
@ -163,6 +172,51 @@ static status_t process_server_hello(private_tls_peer_t *this,
|
||||||
|
|
||||||
memcpy(this->server_random, random.ptr, sizeof(this->server_random));
|
memcpy(this->server_random, random.ptr, sizeof(this->server_random));
|
||||||
|
|
||||||
|
bio_reader_t *extension_reader = bio_reader_create(ext);
|
||||||
|
|
||||||
|
/* parse extension to decide which tls version of the state machine we
|
||||||
|
* want to go
|
||||||
|
*/
|
||||||
|
while (offset < ext.len)
|
||||||
|
{
|
||||||
|
chunk_t extension_payload = chunk_empty;
|
||||||
|
|
||||||
|
extension_reader->read_uint16(extension_reader, &extension_type);
|
||||||
|
extension_reader->read_uint16(extension_reader, &extension_length);
|
||||||
|
offset += extension_length + 4;
|
||||||
|
|
||||||
|
if (!extension_reader->read_data(extension_reader,
|
||||||
|
extension_length,
|
||||||
|
&extension_payload))
|
||||||
|
{
|
||||||
|
DBG2(DBG_TLS, "unable to read extension payload data");
|
||||||
|
}
|
||||||
|
|
||||||
|
bio_reader_t *ext_payload_reader = bio_reader_create(extension_payload);
|
||||||
|
|
||||||
|
switch (extension_type)
|
||||||
|
{
|
||||||
|
case TLS_EXT_SUPPORTED_VERSIONS:
|
||||||
|
ext_payload_reader->read_uint16(ext_payload_reader, &version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_EXT_KEY_SHARE:
|
||||||
|
ext_payload_reader->read_uint16(ext_payload_reader, &key_type);
|
||||||
|
ext_payload_reader->read_uint16(ext_payload_reader, &key_length);
|
||||||
|
if (!ext_payload_reader->read_data(ext_payload_reader,
|
||||||
|
key_length,
|
||||||
|
&ext_key_share))
|
||||||
|
{
|
||||||
|
DBG2(DBG_TLS, "no valid key share found in extension");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ext_payload_reader->destroy(ext_payload_reader);
|
||||||
|
}
|
||||||
|
extension_reader->destroy(extension_reader);
|
||||||
|
|
||||||
if (!this->tls->set_version(this->tls, version))
|
if (!this->tls->set_version(this->tls, version))
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "negotiated version %N not supported",
|
DBG1(DBG_TLS, "negotiated version %N not supported",
|
||||||
|
@ -171,17 +225,24 @@ static status_t process_server_hello(private_tls_peer_t *this,
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chunk_equals(this->session, session))
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
{
|
{
|
||||||
suite = this->crypto->resume_session(this->crypto, session, this->server,
|
if (chunk_equals(this->session, session))
|
||||||
chunk_from_thing(this->client_random),
|
|
||||||
chunk_from_thing(this->server_random));
|
|
||||||
if (suite)
|
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "resumed %N using suite %N",
|
suite = this->crypto->resume_session(this->crypto, session,
|
||||||
tls_version_names, version, tls_cipher_suite_names, suite);
|
this->server, chunk_from_thing
|
||||||
this->resume = TRUE;
|
(this->client_random),
|
||||||
|
chunk_from_thing
|
||||||
|
(this->server_random));
|
||||||
|
if (suite)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "resumed %N using suite %N",
|
||||||
|
tls_version_names, version, tls_cipher_suite_names, suite);
|
||||||
|
this->resume = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
DESTROY_IF(this->dh);
|
||||||
|
this->dh = NULL;
|
||||||
}
|
}
|
||||||
if (!suite)
|
if (!suite)
|
||||||
{
|
{
|
||||||
|
@ -198,10 +259,101 @@ static status_t process_server_hello(private_tls_peer_t *this,
|
||||||
free(this->session.ptr);
|
free(this->session.ptr);
|
||||||
this->session = chunk_clone(session);
|
this->session = chunk_clone(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->tls->get_version_max(this->tls) == TLS_1_3)
|
||||||
|
{
|
||||||
|
chunk_t shared_secret;
|
||||||
|
|
||||||
|
if (key_type != CURVE_25519 &&
|
||||||
|
!this->dh->set_other_public_value(this->dh, ext_key_share))
|
||||||
|
{
|
||||||
|
DBG2(DBG_TLS, "server key share unable to save");
|
||||||
|
}
|
||||||
|
if (!this->dh->get_shared_secret(this->dh, &shared_secret))
|
||||||
|
{
|
||||||
|
DBG2(DBG_TLS, "No shared secret key found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->crypto->derive_handshake_secret(this->crypto, shared_secret))
|
||||||
|
{
|
||||||
|
DBG2(DBG_TLS, "derive handshake traffic secret failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->state = STATE_HELLO_RECEIVED;
|
this->state = STATE_HELLO_RECEIVED;
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a server encrypted extensions message
|
||||||
|
*/
|
||||||
|
static status_t process_encrypted_extensions(private_tls_peer_t *this,
|
||||||
|
bio_reader_t *reader)
|
||||||
|
{
|
||||||
|
uint16_t length;
|
||||||
|
chunk_t ext = chunk_empty;
|
||||||
|
int offset = 0;
|
||||||
|
uint16_t extension_type, extension_length;
|
||||||
|
|
||||||
|
this->crypto->append_handshake(this->crypto,
|
||||||
|
TLS_ENCRYPTED_EXTENSIONS, reader->peek(reader));
|
||||||
|
|
||||||
|
|
||||||
|
if (!reader->read_uint16(reader, &length) ||
|
||||||
|
(reader->remaining(reader) && !reader->read_data16(reader, &ext)))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "received invalid EncryptedExtensions");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
if (ext.len == 0)
|
||||||
|
{
|
||||||
|
this->state = STATE_ENCRYPTED_EXTENSIONS_RECEIVED;
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bio_reader_t *extension_reader = bio_reader_create(ext);
|
||||||
|
|
||||||
|
while (offset < ext.len)
|
||||||
|
{
|
||||||
|
chunk_t extension_payload = chunk_empty;
|
||||||
|
extension_reader->read_uint16(extension_reader, &extension_type);
|
||||||
|
extension_reader->read_uint16(extension_reader, &extension_length);
|
||||||
|
offset += extension_length + 4;
|
||||||
|
|
||||||
|
if (!extension_reader->read_data(extension_reader,
|
||||||
|
extension_length,
|
||||||
|
&extension_payload))
|
||||||
|
{
|
||||||
|
DBG2(DBG_TLS, "unable to read extension payload data");
|
||||||
|
}
|
||||||
|
switch (extension_type)
|
||||||
|
{
|
||||||
|
/* fall through because not supported so far */
|
||||||
|
case TLS_EXT_SERVER_NAME:
|
||||||
|
case TLS_EXT_MAX_FRAGMENT_LENGTH:
|
||||||
|
case TLS_EXT_SUPPORTED_GROUPS:
|
||||||
|
case TLS_EXT_USE_SRTP:
|
||||||
|
case TLS_EXT_HEARTBEAT:
|
||||||
|
case TLS_EXT_APPLICATION_LAYER_PROTOCOL_NEGOTIATION:
|
||||||
|
case TLS_SERVER_CERTIFICATE_TYPE:
|
||||||
|
this->state = STATE_ENCRYPTED_EXTENSIONS_RECEIVED;
|
||||||
|
extension_reader->destroy(extension_reader);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG1(DBG_TLS, "received forbidden EncryptedExtensions");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL,
|
||||||
|
TLS_ILLEGAL_PARAMETER);
|
||||||
|
extension_reader->destroy(extension_reader);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a server certificate is acceptable for the given server identity
|
* Check if a server certificate is acceptable for the given server identity
|
||||||
*/
|
*/
|
||||||
|
@ -252,6 +404,20 @@ static status_t process_certificate(private_tls_peer_t *this,
|
||||||
this->crypto->append_handshake(this->crypto,
|
this->crypto->append_handshake(this->crypto,
|
||||||
TLS_CERTIFICATE, reader->peek(reader));
|
TLS_CERTIFICATE, reader->peek(reader));
|
||||||
|
|
||||||
|
if (this->tls->get_version_max(this->tls) > TLS_1_2)
|
||||||
|
{
|
||||||
|
if (!reader->read_data8(reader, &data))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "certificate request context invalid");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
if (data.len > 0)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "certificate request context available,"
|
||||||
|
"but CertificateRequest not received");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!reader->read_data24(reader, &data))
|
if (!reader->read_data24(reader, &data))
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "certificate message header invalid");
|
DBG1(DBG_TLS, "certificate message header invalid");
|
||||||
|
@ -300,12 +466,69 @@ static status_t process_certificate(private_tls_peer_t *this,
|
||||||
DBG1(DBG_TLS, "parsing TLS certificate failed, skipped");
|
DBG1(DBG_TLS, "parsing TLS certificate failed, skipped");
|
||||||
this->alert->add(this->alert, TLS_WARNING, TLS_BAD_CERTIFICATE);
|
this->alert->add(this->alert, TLS_WARNING, TLS_BAD_CERTIFICATE);
|
||||||
}
|
}
|
||||||
|
if (this->tls->get_version_max(this->tls) > TLS_1_2)
|
||||||
|
{
|
||||||
|
if (!certs->read_data16(certs, &data))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "reading extension field of certificate failed",
|
||||||
|
&data);
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
certs->destroy(certs);
|
certs->destroy(certs);
|
||||||
this->state = STATE_CERT_RECEIVED;
|
this->state = STATE_CERT_RECEIVED;
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process Certificate verify
|
||||||
|
*/
|
||||||
|
static status_t process_cert_verify(private_tls_peer_t *this,
|
||||||
|
bio_reader_t *reader)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
public_key_t *public;
|
||||||
|
auth_cfg_t *auth;
|
||||||
|
bio_reader_t *sig;
|
||||||
|
bool verified = FALSE;
|
||||||
|
|
||||||
|
enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
|
||||||
|
KEY_ANY, this->server,
|
||||||
|
this->server_auth, TRUE);
|
||||||
|
while (enumerator->enumerate(enumerator, &public, &auth))
|
||||||
|
{
|
||||||
|
sig = bio_reader_create(reader->peek(reader));
|
||||||
|
verified = this->crypto->verify_handshake(this->crypto, public, sig);
|
||||||
|
sig->destroy(sig);
|
||||||
|
if (verified)
|
||||||
|
{
|
||||||
|
this->server_auth->merge(this->server_auth, auth, FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DBG1(DBG_TLS, "signature verification failed, trying another key");
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
if (!verified)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "no trusted certificate found for '%Y' to verify TLS peer",
|
||||||
|
this->server);
|
||||||
|
this->server->destroy(this->server);
|
||||||
|
this->peer = NULL;
|
||||||
|
this->state = STATE_KEY_EXCHANGE_RECEIVED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->state = STATE_CERT_VERIFY_RECEIVED;
|
||||||
|
}
|
||||||
|
this->crypto->append_handshake(this->crypto,
|
||||||
|
TLS_CERTIFICATE_VERIFY, reader->peek(reader));
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a trusted public key to encrypt/verify key exchange data
|
* Find a trusted public key to encrypt/verify key exchange data
|
||||||
*/
|
*/
|
||||||
|
@ -407,10 +630,10 @@ static status_t process_modp_key_exchange(private_tls_peer_t *this,
|
||||||
* Get the EC group for a TLS named curve
|
* Get the EC group for a TLS named curve
|
||||||
*/
|
*/
|
||||||
static diffie_hellman_group_t curve_to_ec_group(private_tls_peer_t *this,
|
static diffie_hellman_group_t curve_to_ec_group(private_tls_peer_t *this,
|
||||||
tls_named_curve_t curve)
|
tls_named_group_t curve)
|
||||||
{
|
{
|
||||||
diffie_hellman_group_t group;
|
diffie_hellman_group_t group;
|
||||||
tls_named_curve_t current;
|
tls_named_group_t current;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
|
|
||||||
enumerator = this->crypto->create_ec_enumerator(this->crypto);
|
enumerator = this->crypto->create_ec_enumerator(this->crypto);
|
||||||
|
@ -464,7 +687,7 @@ static status_t process_ec_key_exchange(private_tls_peer_t *this,
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "ECDH curve %N not supported",
|
DBG1(DBG_TLS, "ECDH curve %N not supported",
|
||||||
tls_named_curve_names, curve);
|
tls_named_group_names, curve);
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
@ -569,7 +792,7 @@ static status_t process_certreq(private_tls_peer_t *this, bio_reader_t *reader)
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
this->cert_types = chunk_clone(types);
|
this->cert_types = chunk_clone(types);
|
||||||
if (this->tls->get_version(this->tls) >= TLS_1_2)
|
if (this->tls->get_version_max(this->tls) >= TLS_1_2)
|
||||||
{
|
{
|
||||||
if (!reader->read_data16(reader, &hashsig))
|
if (!reader->read_data16(reader, &hashsig))
|
||||||
{
|
{
|
||||||
|
@ -634,26 +857,54 @@ static status_t process_hello_done(private_tls_peer_t *this,
|
||||||
*/
|
*/
|
||||||
static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader)
|
static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader)
|
||||||
{
|
{
|
||||||
chunk_t received;
|
chunk_t received, verify_data;
|
||||||
char buf[12];
|
char buf[12];
|
||||||
|
uint32_t hash_length;
|
||||||
|
|
||||||
if (!reader->read_data(reader, sizeof(buf), &received))
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "received server finished too short");
|
if (!reader->read_data(reader, sizeof(buf), &received))
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
{
|
||||||
return NEED_MORE;
|
DBG1(DBG_TLS, "received server finished too short");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
if (!this->crypto->calculate_finished(this->crypto, "server finished",
|
||||||
|
buf))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "calculating server finished failed");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
if (!chunk_equals_const(received, chunk_from_thing(buf)))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "received server finished invalid");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
|
else
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "calculating server finished failed");
|
hash_length = reader->remaining(reader);
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
if (!reader->read_data(reader, hash_length, &received))
|
||||||
return NEED_MORE;
|
{
|
||||||
}
|
DBG1(DBG_TLS, "received server finished too short");
|
||||||
if (!chunk_equals_const(received, chunk_from_thing(buf)))
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
||||||
{
|
return NEED_MORE;
|
||||||
DBG1(DBG_TLS, "received server finished invalid");
|
}
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
|
if (!this->crypto->calculate_finished_tls13(this->crypto, true,
|
||||||
return NEED_MORE;
|
&verify_data))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "calculating server finished failed");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
if (!chunk_equals(received, verify_data))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "received server finished invalid");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this->state = STATE_FINISHED_RECEIVED;
|
this->state = STATE_FINISHED_RECEIVED;
|
||||||
this->crypto->append_handshake(this->crypto, TLS_FINISHED, received);
|
this->crypto->append_handshake(this->crypto, TLS_FINISHED, received);
|
||||||
|
@ -661,61 +912,142 @@ static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader)
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process New Session Ticket message
|
||||||
|
*/
|
||||||
|
static status_t process_new_session_ticket(private_tls_peer_t *this,
|
||||||
|
bio_reader_t *reader)
|
||||||
|
{
|
||||||
|
uint32_t ticket_lifetime, ticket_age_add;
|
||||||
|
chunk_t ticket_nonce, ticket, extensions;
|
||||||
|
|
||||||
|
if (!reader->read_uint32(reader, &ticket_lifetime) ||
|
||||||
|
!reader->read_uint32(reader, &ticket_age_add) ||
|
||||||
|
!reader->read_data8(reader, &ticket_nonce) ||
|
||||||
|
!reader->read_data16(reader, &ticket) ||
|
||||||
|
!reader->read_data16(reader, &extensions))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "received invalid NewSessionTicket");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(tls_handshake_t, process, status_t,
|
METHOD(tls_handshake_t, process, status_t,
|
||||||
private_tls_peer_t *this, tls_handshake_type_t type, bio_reader_t *reader)
|
private_tls_peer_t *this, tls_handshake_type_t type, bio_reader_t *reader)
|
||||||
{
|
{
|
||||||
tls_handshake_type_t expected;
|
tls_handshake_type_t expected;
|
||||||
|
|
||||||
switch (this->state)
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
{
|
{
|
||||||
case STATE_HELLO_SENT:
|
switch (this->state)
|
||||||
if (type == TLS_SERVER_HELLO)
|
{
|
||||||
{
|
case STATE_HELLO_SENT:
|
||||||
return process_server_hello(this, reader);
|
if (type == TLS_SERVER_HELLO)
|
||||||
}
|
{
|
||||||
expected = TLS_SERVER_HELLO;
|
return process_server_hello(this, reader);
|
||||||
break;
|
}
|
||||||
case STATE_HELLO_RECEIVED:
|
expected = TLS_SERVER_HELLO;
|
||||||
if (type == TLS_CERTIFICATE)
|
break;
|
||||||
{
|
case STATE_HELLO_RECEIVED:
|
||||||
return process_certificate(this, reader);
|
if (type == TLS_CERTIFICATE)
|
||||||
}
|
{
|
||||||
expected = TLS_CERTIFICATE;
|
return process_certificate(this, reader);
|
||||||
break;
|
}
|
||||||
case STATE_CERT_RECEIVED:
|
expected = TLS_CERTIFICATE;
|
||||||
if (type == TLS_SERVER_KEY_EXCHANGE)
|
break;
|
||||||
{
|
case STATE_CERT_RECEIVED:
|
||||||
return process_key_exchange(this, reader);
|
if (type == TLS_SERVER_KEY_EXCHANGE)
|
||||||
}
|
{
|
||||||
/* fall through since TLS_SERVER_KEY_EXCHANGE is optional */
|
return process_key_exchange(this, reader);
|
||||||
case STATE_KEY_EXCHANGE_RECEIVED:
|
}
|
||||||
if (type == TLS_CERTIFICATE_REQUEST)
|
/* fall through since TLS_SERVER_KEY_EXCHANGE is optional */
|
||||||
{
|
case STATE_KEY_EXCHANGE_RECEIVED:
|
||||||
return process_certreq(this, reader);
|
if (type == TLS_CERTIFICATE_REQUEST)
|
||||||
}
|
{
|
||||||
/* no cert request, server does not want to authenticate us */
|
return process_certreq(this, reader);
|
||||||
DESTROY_IF(this->peer);
|
}
|
||||||
this->peer = NULL;
|
/* no cert request, server does not want to authenticate us */
|
||||||
/* fall through since TLS_CERTIFICATE_REQUEST is optional */
|
DESTROY_IF(this->peer);
|
||||||
case STATE_CERTREQ_RECEIVED:
|
this->peer = NULL;
|
||||||
if (type == TLS_SERVER_HELLO_DONE)
|
/* fall through since TLS_CERTIFICATE_REQUEST is optional */
|
||||||
{
|
case STATE_CERTREQ_RECEIVED:
|
||||||
return process_hello_done(this, reader);
|
if (type == TLS_SERVER_HELLO_DONE)
|
||||||
}
|
{
|
||||||
expected = TLS_SERVER_HELLO_DONE;
|
return process_hello_done(this, reader);
|
||||||
break;
|
}
|
||||||
case STATE_CIPHERSPEC_CHANGED_IN:
|
expected = TLS_SERVER_HELLO_DONE;
|
||||||
if (type == TLS_FINISHED)
|
break;
|
||||||
{
|
case STATE_CIPHERSPEC_CHANGED_IN:
|
||||||
return process_finished(this, reader);
|
if (type == TLS_FINISHED)
|
||||||
}
|
{
|
||||||
expected = TLS_FINISHED;
|
return process_finished(this, reader);
|
||||||
break;
|
}
|
||||||
default:
|
expected = TLS_FINISHED;
|
||||||
DBG1(DBG_TLS, "TLS %N not expected in current state",
|
break;
|
||||||
tls_handshake_type_names, type);
|
default:
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE);
|
DBG1(DBG_TLS, "TLS %N not expected in current state",
|
||||||
return NEED_MORE;
|
tls_handshake_type_names, type);
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (this->state)
|
||||||
|
{
|
||||||
|
case STATE_HELLO_SENT:
|
||||||
|
if (type == TLS_SERVER_HELLO)
|
||||||
|
{
|
||||||
|
return process_server_hello(this, reader);
|
||||||
|
}
|
||||||
|
expected = TLS_SERVER_HELLO;
|
||||||
|
break;
|
||||||
|
case STATE_CIPHERSPEC_CHANGED_IN:
|
||||||
|
case STATE_HELLO_RECEIVED:
|
||||||
|
if (type == TLS_ENCRYPTED_EXTENSIONS)
|
||||||
|
{
|
||||||
|
return process_encrypted_extensions(this, reader);
|
||||||
|
}
|
||||||
|
expected = TLS_ENCRYPTED_EXTENSIONS;
|
||||||
|
break;
|
||||||
|
case STATE_ENCRYPTED_EXTENSIONS_RECEIVED:
|
||||||
|
if (type == TLS_CERTIFICATE)
|
||||||
|
{
|
||||||
|
return process_certificate(this, reader);
|
||||||
|
}
|
||||||
|
expected = TLS_CERTIFICATE;
|
||||||
|
break;
|
||||||
|
case STATE_CERT_RECEIVED:
|
||||||
|
if (type == TLS_CERTIFICATE_VERIFY)
|
||||||
|
{
|
||||||
|
return process_cert_verify(this, reader);
|
||||||
|
}
|
||||||
|
expected = TLS_CERTIFICATE_VERIFY;
|
||||||
|
break;
|
||||||
|
case STATE_CERT_VERIFY_RECEIVED:
|
||||||
|
if (type == TLS_FINISHED)
|
||||||
|
{
|
||||||
|
return process_finished(this, reader);
|
||||||
|
}
|
||||||
|
expected = TLS_FINISHED;
|
||||||
|
break;
|
||||||
|
case STATE_FINISHED_RECEIVED:
|
||||||
|
return NEED_MORE;
|
||||||
|
case STATE_FINISHED_SENT_KEY_SWITCHED:
|
||||||
|
if (type == TLS_NEW_SESSION_TICKET)
|
||||||
|
{
|
||||||
|
return process_new_session_ticket(this, reader);
|
||||||
|
}
|
||||||
|
expected = TLS_NEW_SESSION_TICKET;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG1(DBG_TLS, "TLS %N not expected in current state",
|
||||||
|
tls_handshake_type_names, type);
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DBG1(DBG_TLS, "TLS %N expected, but received %N",
|
DBG1(DBG_TLS, "TLS %N expected, but received %N",
|
||||||
tls_handshake_type_names, expected, tls_handshake_type_names, type);
|
tls_handshake_type_names, expected, tls_handshake_type_names, type);
|
||||||
|
@ -731,11 +1063,13 @@ static status_t send_client_hello(private_tls_peer_t *this,
|
||||||
{
|
{
|
||||||
tls_cipher_suite_t *suites;
|
tls_cipher_suite_t *suites;
|
||||||
bio_writer_t *extensions, *curves = NULL;
|
bio_writer_t *extensions, *curves = NULL;
|
||||||
tls_version_t version;
|
tls_version_t version_max, version_min;
|
||||||
tls_named_curve_t curve;
|
tls_named_group_t curve;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
int count, i;
|
int count, i, v;
|
||||||
rng_t *rng;
|
rng_t *rng;
|
||||||
|
chunk_t pub;
|
||||||
|
uint8_t nof_tls_versions;
|
||||||
|
|
||||||
htoun32(&this->client_random, time(NULL));
|
htoun32(&this->client_random, time(NULL));
|
||||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||||
|
@ -750,10 +1084,21 @@ static status_t send_client_hello(private_tls_peer_t *this,
|
||||||
}
|
}
|
||||||
rng->destroy(rng);
|
rng->destroy(rng);
|
||||||
|
|
||||||
/* TLS version */
|
/* client key generation */
|
||||||
version = this->tls->get_version(this->tls);
|
this->dh = lib->crypto->create_dh(lib->crypto, CURVE_25519);
|
||||||
this->hello_version = version;
|
|
||||||
writer->write_uint16(writer, version);
|
/* TLS version_max in handshake protocol */
|
||||||
|
version_max = this->tls->get_version_max(this->tls);
|
||||||
|
version_min = this->tls->get_version_min(this->tls);
|
||||||
|
if (version_max < TLS_1_3)
|
||||||
|
{
|
||||||
|
this->hello_version = version_max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->hello_version = TLS_1_2;
|
||||||
|
}
|
||||||
|
writer->write_uint16(writer, this->hello_version);
|
||||||
writer->write_data(writer, chunk_from_thing(this->client_random));
|
writer->write_data(writer, chunk_from_thing(this->client_random));
|
||||||
|
|
||||||
/* session identifier */
|
/* session identifier */
|
||||||
|
@ -774,16 +1119,29 @@ static status_t send_client_hello(private_tls_peer_t *this,
|
||||||
|
|
||||||
extensions = bio_writer_create(32);
|
extensions = bio_writer_create(32);
|
||||||
|
|
||||||
extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS);
|
if (this->server->get_type(this->server) == ID_FQDN)
|
||||||
this->crypto->get_signature_algorithms(this->crypto, extensions);
|
{
|
||||||
|
bio_writer_t *names;
|
||||||
|
|
||||||
/* add supported Elliptic Curves, if any */
|
DBG2(DBG_TLS, "sending extension: Server Name Indication for '%Y'",
|
||||||
|
this->server);
|
||||||
|
names = bio_writer_create(8);
|
||||||
|
names->write_uint8(names, TLS_NAME_TYPE_HOST_NAME);
|
||||||
|
names->write_data16(names, this->server->get_encoding(this->server));
|
||||||
|
names->wrap16(names);
|
||||||
|
extensions->write_uint16(extensions, TLS_EXT_SERVER_NAME);
|
||||||
|
extensions->write_data16(extensions, names->get_buf(names));
|
||||||
|
names->destroy(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG2(DBG_TLS, "sending extension: %N",
|
||||||
|
tls_extension_names, TLS_EXT_SUPPORTED_GROUPS);
|
||||||
enumerator = this->crypto->create_ec_enumerator(this->crypto);
|
enumerator = this->crypto->create_ec_enumerator(this->crypto);
|
||||||
while (enumerator->enumerate(enumerator, NULL, &curve))
|
while (enumerator->enumerate(enumerator, NULL, &curve))
|
||||||
{
|
{
|
||||||
if (!curves)
|
if (!curves)
|
||||||
{
|
{
|
||||||
extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES);
|
extensions->write_uint16(extensions, TLS_EXT_SUPPORTED_GROUPS);
|
||||||
curves = bio_writer_create(16);
|
curves = bio_writer_create(16);
|
||||||
}
|
}
|
||||||
curves->write_uint16(curves, curve);
|
curves->write_uint16(curves, curve);
|
||||||
|
@ -791,6 +1149,10 @@ static status_t send_client_hello(private_tls_peer_t *this,
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
if (curves)
|
if (curves)
|
||||||
{
|
{
|
||||||
|
if (version_max == TLS_1_3)
|
||||||
|
{
|
||||||
|
curves->write_uint16(curves, TLS_CURVE25519);
|
||||||
|
}
|
||||||
curves->wrap16(curves);
|
curves->wrap16(curves);
|
||||||
extensions->write_data16(extensions, curves->get_buf(curves));
|
extensions->write_data16(extensions, curves->get_buf(curves));
|
||||||
curves->destroy(curves);
|
curves->destroy(curves);
|
||||||
|
@ -801,21 +1163,39 @@ static status_t send_client_hello(private_tls_peer_t *this,
|
||||||
extensions->write_uint8(extensions, 1);
|
extensions->write_uint8(extensions, 1);
|
||||||
extensions->write_uint8(extensions, TLS_EC_POINT_UNCOMPRESSED);
|
extensions->write_uint8(extensions, TLS_EC_POINT_UNCOMPRESSED);
|
||||||
}
|
}
|
||||||
if (this->server->get_type(this->server) == ID_FQDN)
|
|
||||||
|
DBG2(DBG_TLS, "sending extension: %N",
|
||||||
|
tls_extension_names, TLS_EXT_SUPPORTED_VERSIONS);
|
||||||
|
nof_tls_versions = (version_max - version_min + 1)*2;
|
||||||
|
extensions->write_uint16(extensions, TLS_EXT_SUPPORTED_VERSIONS);
|
||||||
|
extensions->write_uint16(extensions, nof_tls_versions+1);
|
||||||
|
extensions->write_uint8(extensions, nof_tls_versions);
|
||||||
|
for (v = version_max; v >= version_min; v--)
|
||||||
{
|
{
|
||||||
bio_writer_t *names;
|
extensions->write_uint16(extensions, v);
|
||||||
|
nof_tls_versions += 2;
|
||||||
DBG2(DBG_TLS, "sending Server Name Indication for '%Y'", this->server);
|
|
||||||
|
|
||||||
names = bio_writer_create(8);
|
|
||||||
names->write_uint8(names, TLS_NAME_TYPE_HOST_NAME);
|
|
||||||
names->write_data16(names, this->server->get_encoding(this->server));
|
|
||||||
names->wrap16(names);
|
|
||||||
extensions->write_uint16(extensions, TLS_EXT_SERVER_NAME);
|
|
||||||
extensions->write_data16(extensions, names->get_buf(names));
|
|
||||||
names->destroy(names);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBG2(DBG_TLS, "sending extension: %N",
|
||||||
|
tls_extension_names, TLS_EXT_SIGNATURE_ALGORITHMS);
|
||||||
|
extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS);
|
||||||
|
this->crypto->get_signature_algorithms(this->crypto, extensions);
|
||||||
|
|
||||||
|
DBG2(DBG_TLS, "sending extension: %N",
|
||||||
|
tls_extension_names, TLS_EXT_KEY_SHARE);
|
||||||
|
if (!this->dh->get_my_public_value(this->dh, &pub))
|
||||||
|
{
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
extensions->write_uint16(extensions, TLS_EXT_KEY_SHARE);
|
||||||
|
extensions->write_uint16(extensions, pub.len+6);
|
||||||
|
extensions->write_uint16(extensions, pub.len+4);
|
||||||
|
extensions->write_uint16(extensions, TLS_CURVE25519);
|
||||||
|
extensions->write_uint16(extensions, pub.len);
|
||||||
|
extensions->write_data(extensions, pub);
|
||||||
|
free(pub.ptr);
|
||||||
|
|
||||||
writer->write_data16(writer, extensions->get_buf(extensions));
|
writer->write_data16(writer, extensions->get_buf(extensions));
|
||||||
extensions->destroy(extensions);
|
extensions->destroy(extensions);
|
||||||
|
|
||||||
|
@ -1071,16 +1451,33 @@ static status_t send_certificate_verify(private_tls_peer_t *this,
|
||||||
static status_t send_finished(private_tls_peer_t *this,
|
static status_t send_finished(private_tls_peer_t *this,
|
||||||
tls_handshake_type_t *type, bio_writer_t *writer)
|
tls_handshake_type_t *type, bio_writer_t *writer)
|
||||||
{
|
{
|
||||||
char buf[12];
|
chunk_t verify_data;
|
||||||
|
|
||||||
if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "calculating client finished data failed");
|
char buf[12];
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
|
||||||
return NEED_MORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer->write_data(writer, chunk_from_thing(buf));
|
if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "calculating client finished data failed");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer->write_data(writer, chunk_from_thing(buf));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!this->crypto->calculate_finished_tls13(this->crypto, false,
|
||||||
|
&verify_data))
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "calculating client finished data failed");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer->write_data(writer, verify_data);
|
||||||
|
}
|
||||||
|
|
||||||
*type = TLS_FINISHED;
|
*type = TLS_FINISHED;
|
||||||
this->state = STATE_FINISHED_SENT;
|
this->state = STATE_FINISHED_SENT;
|
||||||
|
@ -1091,63 +1488,112 @@ static status_t send_finished(private_tls_peer_t *this,
|
||||||
METHOD(tls_handshake_t, build, status_t,
|
METHOD(tls_handshake_t, build, status_t,
|
||||||
private_tls_peer_t *this, tls_handshake_type_t *type, bio_writer_t *writer)
|
private_tls_peer_t *this, tls_handshake_type_t *type, bio_writer_t *writer)
|
||||||
{
|
{
|
||||||
switch (this->state)
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
{
|
{
|
||||||
case STATE_INIT:
|
switch (this->state)
|
||||||
return send_client_hello(this, type, writer);
|
{
|
||||||
case STATE_HELLO_DONE:
|
case STATE_INIT:
|
||||||
if (this->peer)
|
return send_client_hello(this, type, writer);
|
||||||
{
|
case STATE_HELLO_DONE:
|
||||||
return send_certificate(this, type, writer);
|
if (this->peer)
|
||||||
}
|
{
|
||||||
/* otherwise fall through to next state */
|
return send_certificate(this, type, writer);
|
||||||
case STATE_CERT_SENT:
|
}
|
||||||
return send_key_exchange(this, type, writer);
|
/* otherwise fall through to next state */
|
||||||
case STATE_KEY_EXCHANGE_SENT:
|
case STATE_CERT_SENT:
|
||||||
if (this->peer)
|
return send_key_exchange(this, type, writer);
|
||||||
{
|
case STATE_KEY_EXCHANGE_SENT:
|
||||||
return send_certificate_verify(this, type, writer);
|
if (this->peer)
|
||||||
}
|
{
|
||||||
else
|
return send_certificate_verify(this, type, writer);
|
||||||
{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return INVALID_STATE;
|
||||||
|
}
|
||||||
|
case STATE_CIPHERSPEC_CHANGED_OUT:
|
||||||
|
return send_finished(this, type, writer);
|
||||||
|
default:
|
||||||
return INVALID_STATE;
|
return INVALID_STATE;
|
||||||
}
|
}
|
||||||
case STATE_CIPHERSPEC_CHANGED_OUT:
|
|
||||||
return send_finished(this, type, writer);
|
|
||||||
default:
|
|
||||||
return INVALID_STATE;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (this->state)
|
||||||
|
{
|
||||||
|
case STATE_INIT:
|
||||||
|
return send_client_hello(this, type, writer);
|
||||||
|
case STATE_HELLO_DONE:
|
||||||
|
/* otherwise fall through to next state */
|
||||||
|
case STATE_CIPHERSPEC_CHANGED_OUT:
|
||||||
|
case STATE_FINISHED_RECEIVED:
|
||||||
|
/* fall through since legacy TLS and TLS 1.3
|
||||||
|
* expect the same message */
|
||||||
|
return send_finished(this, type, writer);
|
||||||
|
case STATE_FINISHED_SENT:
|
||||||
|
this->crypto->derive_app_secret(this->crypto);
|
||||||
|
this->crypto->change_cipher(this->crypto, TRUE);
|
||||||
|
this->crypto->change_cipher(this->crypto, FALSE);
|
||||||
|
this->state = STATE_FINISHED_SENT_KEY_SWITCHED;
|
||||||
|
return SUCCESS;
|
||||||
|
case STATE_FINISHED_SENT_KEY_SWITCHED:
|
||||||
|
return SUCCESS;
|
||||||
|
default:
|
||||||
|
return INVALID_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(tls_handshake_t, cipherspec_changed, bool,
|
METHOD(tls_handshake_t, cipherspec_changed, bool,
|
||||||
private_tls_peer_t *this, bool inbound)
|
private_tls_peer_t *this, bool inbound)
|
||||||
{
|
{
|
||||||
if (inbound)
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
{
|
{
|
||||||
if (this->resume)
|
if (inbound)
|
||||||
{
|
{
|
||||||
return this->state == STATE_HELLO_RECEIVED;
|
if (this->resume)
|
||||||
|
{
|
||||||
|
return this->state == STATE_HELLO_RECEIVED;
|
||||||
|
}
|
||||||
|
return this->state == STATE_FINISHED_SENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this->resume)
|
||||||
|
{
|
||||||
|
return this->state == STATE_FINISHED_RECEIVED;
|
||||||
|
}
|
||||||
|
if (this->peer)
|
||||||
|
{
|
||||||
|
return this->state == STATE_VERIFY_SENT;
|
||||||
|
}
|
||||||
|
return this->state == STATE_KEY_EXCHANGE_SENT;
|
||||||
|
|
||||||
}
|
}
|
||||||
return this->state == STATE_FINISHED_SENT;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (this->resume)
|
if (inbound)
|
||||||
{
|
{
|
||||||
return this->state == STATE_FINISHED_RECEIVED;
|
return this->state == STATE_HELLO_RECEIVED;
|
||||||
}
|
}
|
||||||
if (this->peer)
|
else
|
||||||
{
|
{
|
||||||
return this->state == STATE_VERIFY_SENT;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return this->state == STATE_KEY_EXCHANGE_SENT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(tls_handshake_t, change_cipherspec, void,
|
METHOD(tls_handshake_t, change_cipherspec, void,
|
||||||
private_tls_peer_t *this, bool inbound)
|
private_tls_peer_t *this, bool inbound)
|
||||||
{
|
{
|
||||||
this->crypto->change_cipher(this->crypto, inbound);
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
|
{
|
||||||
|
this->crypto->change_cipher(this->crypto, inbound);
|
||||||
|
}
|
||||||
|
|
||||||
if (inbound)
|
if (inbound)
|
||||||
{
|
{
|
||||||
this->state = STATE_CIPHERSPEC_CHANGED_IN;
|
this->state = STATE_CIPHERSPEC_CHANGED_IN;
|
||||||
|
@ -1161,11 +1607,19 @@ METHOD(tls_handshake_t, change_cipherspec, void,
|
||||||
METHOD(tls_handshake_t, finished, bool,
|
METHOD(tls_handshake_t, finished, bool,
|
||||||
private_tls_peer_t *this)
|
private_tls_peer_t *this)
|
||||||
{
|
{
|
||||||
if (this->resume)
|
if (this->tls->get_version_max(this->tls) < TLS_1_3)
|
||||||
{
|
{
|
||||||
|
if (this->resume)
|
||||||
|
{
|
||||||
return this->state == STATE_FINISHED_SENT;
|
return this->state == STATE_FINISHED_SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->state == STATE_FINISHED_RECEIVED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this->state == STATE_FINISHED_SENT_KEY_SWITCHED;
|
||||||
}
|
}
|
||||||
return this->state == STATE_FINISHED_RECEIVED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(tls_handshake_t, get_peer_id, identification_t*,
|
METHOD(tls_handshake_t, get_peer_id, identification_t*,
|
||||||
|
|
|
@ -73,23 +73,19 @@ METHOD(tls_protection_t, process, status_t,
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->aead_in)
|
if (this-> version < TLS_1_3 ||
|
||||||
|
type == TLS_APPLICATION_DATA)
|
||||||
{
|
{
|
||||||
if (!this->aead_in->decrypt(this->aead_in, this->version,
|
if (this->aead_in)
|
||||||
&type, this->seq_in, &data))
|
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "TLS record decryption failed");
|
if (!this->aead_in->decrypt(this->aead_in, this->version,
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
|
&type, this->seq_in, &data))
|
||||||
return NEED_MORE;
|
{
|
||||||
|
DBG1(DBG_TLS, "TLS record decryption failed");
|
||||||
|
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (type == TLS_CHANGE_CIPHER_SPEC)
|
|
||||||
{
|
|
||||||
this->seq_in = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->seq_in++;
|
this->seq_in++;
|
||||||
}
|
}
|
||||||
return this->compression->process(this->compression, type, data);
|
return this->compression->process(this->compression, type, data);
|
||||||
|
@ -103,9 +99,8 @@ METHOD(tls_protection_t, build, status_t,
|
||||||
status = this->compression->build(this->compression, type, data);
|
status = this->compression->build(this->compression, type, data);
|
||||||
if (status == NEED_MORE)
|
if (status == NEED_MORE)
|
||||||
{
|
{
|
||||||
if (*type == TLS_CHANGE_CIPHER_SPEC)
|
if (this-> version < TLS_1_3 && *type == TLS_CHANGE_CIPHER_SPEC)
|
||||||
{
|
{
|
||||||
this->seq_out = 0;
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
if (this->aead_out)
|
if (this->aead_out)
|
||||||
|
@ -129,10 +124,12 @@ METHOD(tls_protection_t, set_cipher, void,
|
||||||
if (inbound)
|
if (inbound)
|
||||||
{
|
{
|
||||||
this->aead_in = aead;
|
this->aead_in = aead;
|
||||||
|
this->seq_in = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->aead_out = aead;
|
this->aead_out = aead;
|
||||||
|
this->seq_out = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,7 @@ static status_t process_client_hello(private_tls_server_t *this,
|
||||||
case TLS_EXT_SIGNATURE_ALGORITHMS:
|
case TLS_EXT_SIGNATURE_ALGORITHMS:
|
||||||
this->hashsig = chunk_clone(ext);
|
this->hashsig = chunk_clone(ext);
|
||||||
break;
|
break;
|
||||||
case TLS_EXT_ELLIPTIC_CURVES:
|
case TLS_EXT_SUPPORTED_GROUPS:
|
||||||
this->curves_received = TRUE;
|
this->curves_received = TRUE;
|
||||||
this->curves = chunk_clone(ext);
|
this->curves = chunk_clone(ext);
|
||||||
break;
|
break;
|
||||||
|
@ -299,7 +299,7 @@ static status_t process_client_hello(private_tls_server_t *this,
|
||||||
this->session = chunk_clone(session);
|
this->session = chunk_clone(session);
|
||||||
this->resume = TRUE;
|
this->resume = TRUE;
|
||||||
DBG1(DBG_TLS, "resumed %N using suite %N",
|
DBG1(DBG_TLS, "resumed %N using suite %N",
|
||||||
tls_version_names, this->tls->get_version(this->tls),
|
tls_version_names, this->tls->get_version_max(this->tls),
|
||||||
tls_cipher_suite_names, this->suite);
|
tls_cipher_suite_names, this->suite);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -324,7 +324,7 @@ static status_t process_client_hello(private_tls_server_t *this,
|
||||||
}
|
}
|
||||||
DESTROY_IF(rng);
|
DESTROY_IF(rng);
|
||||||
DBG1(DBG_TLS, "negotiated %N using suite %N",
|
DBG1(DBG_TLS, "negotiated %N using suite %N",
|
||||||
tls_version_names, this->tls->get_version(this->tls),
|
tls_version_names, this->tls->get_version_max(this->tls),
|
||||||
tls_cipher_suite_names, this->suite);
|
tls_cipher_suite_names, this->suite);
|
||||||
}
|
}
|
||||||
this->state = STATE_HELLO_RECEIVED;
|
this->state = STATE_HELLO_RECEIVED;
|
||||||
|
@ -688,7 +688,7 @@ static status_t send_server_hello(private_tls_server_t *this,
|
||||||
tls_handshake_type_t *type, bio_writer_t *writer)
|
tls_handshake_type_t *type, bio_writer_t *writer)
|
||||||
{
|
{
|
||||||
/* TLS version */
|
/* TLS version */
|
||||||
writer->write_uint16(writer, this->tls->get_version(this->tls));
|
writer->write_uint16(writer, this->tls->get_version_max(this->tls));
|
||||||
writer->write_data(writer, chunk_from_thing(this->server_random));
|
writer->write_data(writer, chunk_from_thing(this->server_random));
|
||||||
|
|
||||||
/* session identifier if we have one */
|
/* session identifier if we have one */
|
||||||
|
@ -774,7 +774,7 @@ static status_t send_certificate_request(private_tls_server_t *this,
|
||||||
supported->write_uint8(supported, TLS_ECDSA_SIGN);
|
supported->write_uint8(supported, TLS_ECDSA_SIGN);
|
||||||
writer->write_data8(writer, supported->get_buf(supported));
|
writer->write_data8(writer, supported->get_buf(supported));
|
||||||
supported->destroy(supported);
|
supported->destroy(supported);
|
||||||
if (this->tls->get_version(this->tls) >= TLS_1_2)
|
if (this->tls->get_version_max(this->tls) >= TLS_1_2)
|
||||||
{
|
{
|
||||||
this->crypto->get_signature_algorithms(this->crypto, writer);
|
this->crypto->get_signature_algorithms(this->crypto, writer);
|
||||||
}
|
}
|
||||||
|
@ -805,11 +805,11 @@ static status_t send_certificate_request(private_tls_server_t *this,
|
||||||
/**
|
/**
|
||||||
* Get the TLS curve of a given EC DH group
|
* Get the TLS curve of a given EC DH group
|
||||||
*/
|
*/
|
||||||
static tls_named_curve_t ec_group_to_curve(private_tls_server_t *this,
|
static tls_named_group_t ec_group_to_curve(private_tls_server_t *this,
|
||||||
diffie_hellman_group_t group)
|
diffie_hellman_group_t group)
|
||||||
{
|
{
|
||||||
diffie_hellman_group_t current;
|
diffie_hellman_group_t current;
|
||||||
tls_named_curve_t curve;
|
tls_named_group_t curve;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
|
|
||||||
enumerator = this->crypto->create_ec_enumerator(this->crypto);
|
enumerator = this->crypto->create_ec_enumerator(this->crypto);
|
||||||
|
@ -828,7 +828,7 @@ static tls_named_curve_t ec_group_to_curve(private_tls_server_t *this,
|
||||||
/**
|
/**
|
||||||
* Check if the peer supports a given TLS curve
|
* Check if the peer supports a given TLS curve
|
||||||
*/
|
*/
|
||||||
bool peer_supports_curve(private_tls_server_t *this, tls_named_curve_t curve)
|
bool peer_supports_curve(private_tls_server_t *this, tls_named_group_t curve)
|
||||||
{
|
{
|
||||||
bio_reader_t *reader;
|
bio_reader_t *reader;
|
||||||
uint16_t current;
|
uint16_t current;
|
||||||
|
@ -854,9 +854,9 @@ bool peer_supports_curve(private_tls_server_t *this, tls_named_curve_t curve)
|
||||||
* Try to find a curve supported by both, client and server
|
* Try to find a curve supported by both, client and server
|
||||||
*/
|
*/
|
||||||
static bool find_supported_curve(private_tls_server_t *this,
|
static bool find_supported_curve(private_tls_server_t *this,
|
||||||
tls_named_curve_t *curve)
|
tls_named_group_t *curve)
|
||||||
{
|
{
|
||||||
tls_named_curve_t current;
|
tls_named_group_t current;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
|
|
||||||
enumerator = this->crypto->create_ec_enumerator(this->crypto);
|
enumerator = this->crypto->create_ec_enumerator(this->crypto);
|
||||||
|
@ -881,7 +881,7 @@ static status_t send_server_key_exchange(private_tls_server_t *this,
|
||||||
diffie_hellman_group_t group)
|
diffie_hellman_group_t group)
|
||||||
{
|
{
|
||||||
diffie_hellman_params_t *params = NULL;
|
diffie_hellman_params_t *params = NULL;
|
||||||
tls_named_curve_t curve;
|
tls_named_group_t curve;
|
||||||
chunk_t chunk;
|
chunk_t chunk;
|
||||||
|
|
||||||
if (diffie_hellman_group_is_ec(group))
|
if (diffie_hellman_group_is_ec(group))
|
||||||
|
@ -894,7 +894,7 @@ static status_t send_server_key_exchange(private_tls_server_t *this,
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
DBG2(DBG_TLS, "selected ECDH group %N", tls_named_curve_names, curve);
|
DBG2(DBG_TLS, "selected ECDH group %N", tls_named_group_names, curve);
|
||||||
writer->write_uint8(writer, TLS_ECC_NAMED_CURVE);
|
writer->write_uint8(writer, TLS_ECC_NAMED_CURVE);
|
||||||
writer->write_uint16(writer, curve);
|
writer->write_uint16(writer, curve);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue