diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/auth/dhe_psk.c | 8 | ||||
-rw-r--r-- | lib/auth/psk.c | 4 | ||||
-rw-r--r-- | lib/auth/psk.h | 13 | ||||
-rw-r--r-- | lib/auth/psk_passwd.c | 23 | ||||
-rw-r--r-- | lib/auth/psk_passwd.h | 5 | ||||
-rw-r--r-- | lib/auth/rsa_psk.c | 5 | ||||
-rw-r--r-- | lib/ext/pre_shared_key.c | 352 | ||||
-rw-r--r-- | lib/ext/pre_shared_key.h | 11 | ||||
-rw-r--r-- | lib/handshake-defs.h | 2 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 22 | ||||
-rw-r--r-- | lib/libgnutls.map | 10 | ||||
-rw-r--r-- | lib/psk.c | 163 |
12 files changed, 533 insertions, 85 deletions
diff --git a/lib/auth/dhe_psk.c b/lib/auth/dhe_psk.c index ab5eddd16a..14cf5ba918 100644 --- a/lib/auth/dhe_psk.c +++ b/lib/auth/dhe_psk.c @@ -103,7 +103,7 @@ static int gen_ecdhe_psk_client_kx(gnutls_session_t session, if (cred == NULL) return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); - ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); + ret = _gnutls_find_psk_key(session, cred, &username, &key, NULL, &free); if (ret < 0) return gnutls_assert_val(ret); @@ -146,7 +146,7 @@ static int gen_dhe_psk_client_kx(gnutls_session_t session, if (cred == NULL) return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); - ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); + ret = _gnutls_find_psk_key(session, cred, &username, &key, NULL, &free); if (ret < 0) return gnutls_assert_val(ret); @@ -308,7 +308,7 @@ static int proc_dhe_psk_client_kx(gnutls_session_t session, uint8_t *data, data += username.size + 2; ret = _gnutls_psk_pwd_find_entry(session, info->username, - info->username_len, &psk_key); + info->username_len, &psk_key, NULL); if (ret < 0) return gnutls_assert_val(ret); @@ -374,7 +374,7 @@ static int proc_ecdhe_psk_client_kx(gnutls_session_t session, uint8_t *data, /* should never fail. It will always return a key even if it is * a random one */ ret = _gnutls_psk_pwd_find_entry(session, info->username, - info->username_len, &psk_key); + info->username_len, &psk_key, NULL); if (ret < 0) return gnutls_assert_val(ret); diff --git a/lib/auth/psk.c b/lib/auth/psk.c index 17206f69c5..8ddb239823 100644 --- a/lib/auth/psk.c +++ b/lib/auth/psk.c @@ -136,7 +136,7 @@ int _gnutls_gen_psk_client_kx(gnutls_session_t session, gnutls_buffer_st *data) return GNUTLS_E_INTERNAL_ERROR; } - ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); + ret = _gnutls_find_psk_key(session, cred, &username, &key, NULL, &free); if (ret < 0) return gnutls_assert_val(ret); @@ -224,7 +224,7 @@ static int _gnutls_proc_psk_client_kx(gnutls_session_t session, uint8_t *data, return gnutls_assert_val(ret); ret = _gnutls_psk_pwd_find_entry(session, info->username, - info->username_len, &psk_key); + info->username_len, &psk_key, NULL); if (ret < 0) return gnutls_assert_val(ret); diff --git a/lib/auth/psk.h b/lib/auth/psk.h index 06d7913c85..9e1f94b1fe 100644 --- a/lib/auth/psk.h +++ b/lib/auth/psk.h @@ -36,19 +36,20 @@ typedef struct gnutls_psk_client_credentials_st { gnutls_datum_t username; gnutls_datum_t key; - gnutls_psk_client_credentials_function2 *get_function; - gnutls_psk_client_credentials_function *get_function_legacy; + gnutls_psk_client_credentials_function3 *get_function; + gnutls_psk_client_credentials_function2 *get_function2; + gnutls_psk_client_credentials_function *get_function1; /* TLS 1.3 - The HMAC algorithm to use to compute the binder values */ const mac_entry_st *binder_algo; } psk_client_credentials_st; typedef struct gnutls_psk_server_credentials_st { char *password_file; - /* callback function, instead of reading the - * password files. + /* callback functions, instead of reading the password files. */ - gnutls_psk_server_credentials_function2 *pwd_callback; - gnutls_psk_server_credentials_function *pwd_callback_legacy; + gnutls_psk_server_credentials_function3 *pwd_callback; + gnutls_psk_server_credentials_function2 *pwd_callback2; + gnutls_psk_server_credentials_function *pwd_callback1; /* For DHE_PSK */ gnutls_dh_params_t dh_params; diff --git a/lib/auth/psk_passwd.c b/lib/auth/psk_passwd.c index 70f59c7738..eff339dd17 100644 --- a/lib/auth/psk_passwd.c +++ b/lib/auth/psk_passwd.c @@ -149,7 +149,8 @@ static int _randomize_psk(gnutls_datum_t *psk) * If the user doesn't exist a random password is returned instead. */ int _gnutls_psk_pwd_find_entry(gnutls_session_t session, const char *username, - uint16_t username_len, gnutls_datum_t *psk) + uint16_t username_len, gnutls_datum_t *psk, + gnutls_psk_key_flags *flags) { gnutls_psk_server_credentials_t cred; FILE *fp; @@ -170,8 +171,7 @@ int _gnutls_psk_pwd_find_entry(gnutls_session_t session, const char *username, * set, use it. */ if (cred->pwd_callback != NULL) { - ret = cred->pwd_callback(session, &username_datum, psk); - + ret = cred->pwd_callback(session, &username_datum, psk, flags); if (ret == 1) { /* the user does not exist */ ret = _randomize_psk(psk); if (ret < 0) { @@ -212,6 +212,9 @@ int _gnutls_psk_pwd_find_entry(gnutls_session_t session, const char *username, ret = GNUTLS_E_SRP_PWD_ERROR; goto cleanup; } + if (flags) { + *flags = 0; + } ret = 0; goto cleanup; } @@ -224,6 +227,9 @@ int _gnutls_psk_pwd_find_entry(gnutls_session_t session, const char *username, goto cleanup; } + if (flags) { + *flags = 0; + } ret = 0; cleanup: if (fp != NULL) @@ -241,7 +247,7 @@ cleanup: int _gnutls_find_psk_key(gnutls_session_t session, gnutls_psk_client_credentials_t cred, gnutls_datum_t *username, gnutls_datum_t *key, - int *free) + gnutls_psk_key_flags *flags, int *free) { int ret; @@ -252,11 +258,14 @@ int _gnutls_find_psk_key(gnutls_session_t session, username->size = cred->username.size; key->data = cred->key.data; key->size = cred->key.size; + if (flags) { + *flags = 0; + } } else if (cred->get_function != NULL) { - ret = cred->get_function(session, username, key); - - if (ret) + ret = cred->get_function(session, username, key, flags); + if (ret) { return gnutls_assert_val(ret); + } *free = 1; } else diff --git a/lib/auth/psk_passwd.h b/lib/auth/psk_passwd.h index 18ac72b34b..2f270cc377 100644 --- a/lib/auth/psk_passwd.h +++ b/lib/auth/psk_passwd.h @@ -25,11 +25,12 @@ /* this is locally allocated. It should be freed using the provided function */ int _gnutls_psk_pwd_find_entry(gnutls_session_t, const char *username, - uint16_t username_len, gnutls_datum_t *key); + uint16_t username_len, gnutls_datum_t *key, + gnutls_psk_key_flags *flags); int _gnutls_find_psk_key(gnutls_session_t session, gnutls_psk_client_credentials_t cred, gnutls_datum_t *username, gnutls_datum_t *key, - int *free); + gnutls_psk_key_flags *flags, int *free); #endif /* GNUTLS_LIB_AUTH_PSK_PASSWD_H */ diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c index e9e99761cf..6e3fbbda82 100644 --- a/lib/auth/rsa_psk.c +++ b/lib/auth/rsa_psk.c @@ -193,7 +193,7 @@ static int _gnutls_gen_rsa_psk_client_kx(gnutls_session_t session, return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } - ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); + ret = _gnutls_find_psk_key(session, cred, &username, &key, NULL, &free); if (ret < 0) return gnutls_assert_val(ret); @@ -382,7 +382,8 @@ static int _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, /* find the key of this username */ ret = _gnutls_psk_pwd_find_entry(session, info->username, - strlen(info->username), &pwd_psk); + strlen(info->username), &pwd_psk, + NULL); if (ret < 0) { gnutls_assert(); goto cleanup; diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index 44797bb5ad..f632f972bc 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -35,6 +35,14 @@ #include <ext/pre_shared_key.h> #include <assert.h> +inline static bool +have_psk_credentials(const gnutls_psk_client_credentials_t cred, + gnutls_session_t session) +{ + return (cred->get_function || cred->username.data) && + session->internals.priorities->have_psk; +} + static int compute_psk_from_ticket(const tls13_ticket_st *ticket, gnutls_datum_t *key) { @@ -61,16 +69,45 @@ static int compute_psk_from_ticket(const tls13_ticket_st *ticket, return ret; } +enum binder_type { + BINDER_EXT, + BINDER_RES, + BINDER_IMP +}; + +static const char *get_binder_label(enum binder_type type, size_t *size) +{ + static const char ext_label[] = EXT_BINDER_LABEL; + static const char res_label[] = RES_BINDER_LABEL; + static const char imp_label[] = IMP_BINDER_LABEL; + const char *label; + + switch (type) { + case BINDER_EXT: + label = ext_label; + *size = sizeof(ext_label) - 1; + break; + case BINDER_RES: + label = res_label; + *size = sizeof(res_label) - 1; + break; + case BINDER_IMP: + label = imp_label; + *size = sizeof(imp_label) - 1; + break; + default: + assert(0); + } + + return label; +} + static int compute_binder_key(const mac_entry_st *prf, const uint8_t *key, - size_t keylen, bool resuming, void *out) + size_t keylen, enum binder_type type, void *out) { int ret; - const char ext_label[] = EXT_BINDER_LABEL; - const size_t ext_label_len = sizeof(ext_label) - 1; - const char res_label[] = RES_BINDER_LABEL; - const size_t res_label_len = sizeof(res_label) - 1; - const char *label = resuming ? res_label : ext_label; - size_t label_len = resuming ? res_label_len : ext_label_len; + size_t label_len; + const char *label = get_binder_label(type, &label_len); uint8_t tmp_key[MAX_HASH_SIZE]; /* Compute HKDF-Extract(0, psk) */ @@ -90,8 +127,8 @@ static int compute_binder_key(const mac_entry_st *prf, const uint8_t *key, static int compute_psk_binder(gnutls_session_t session, const mac_entry_st *prf, unsigned binders_length, int exts_length, int ext_offset, const gnutls_datum_t *psk, - const gnutls_datum_t *client_hello, bool resuming, - void *out) + const gnutls_datum_t *client_hello, + enum binder_type type, void *out) { int ret; unsigned client_hello_pos, extensions_len_pos; @@ -176,8 +213,7 @@ static int compute_psk_binder(gnutls_session_t session, const mac_entry_st *prf, } } - ret = compute_binder_key(prf, psk->data, psk->size, resuming, - binder_key); + ret = compute_binder_key(prf, psk->data, psk->size, type, binder_key); if (ret < 0) { gnutls_assert(); goto error; @@ -264,6 +300,172 @@ int _gnutls_generate_early_secrets_for_psk(gnutls_session_t session) return 0; } +/** + * gnutls_psk_format_imported_identity: + * @identity: external identity + * @context: optional contextual information + * @version: protocol version to which the PSK is imported + * @hash: hash algorithm used for KDF + * @imported_identity: where the imported identity is stored + * + * This formats an external PSK identity @identity into an imported + * form, described in RFC 9258 as ImportedIdentity. + * + * Upon success, the data field of @imported_identity is allocated + * using gnutls_malloc() and the caller must free the memory after + * use. + * + * Returns: %GNUTLS_E_SUCCESS (0) on success, otherwise a negative error code. + * Since: 3.8.1 + */ +int gnutls_psk_format_imported_identity(const gnutls_datum_t *identity, + const gnutls_datum_t *context, + gnutls_protocol_t version, + gnutls_digest_algorithm_t hash, + gnutls_datum_t *imported_identity) +{ + gnutls_buffer_st buf; + const version_entry_st *ver = version_to_entry(version); + const mac_entry_st *prf = hash_to_entry(hash); + uint16_t target_protocol; + uint16_t target_kdf; + int ret; + + _gnutls_buffer_init(&buf); + + /* external_identity */ + ret = _gnutls_buffer_append_data_prefix(&buf, 16, identity->data, + identity->size); + if (ret < 0) { + goto error; + } + + /* context */ + ret = _gnutls_buffer_append_data_prefix(&buf, 16, context->data, + context->size); + if (ret < 0) { + goto error; + } + + /* target_protocol */ + target_protocol = ver->major << 8 | ver->minor; + ret = _gnutls_buffer_append_prefix(&buf, 16, target_protocol); + if (ret < 0) { + goto error; + } + + /* target_kdf */ + switch (prf->id) { + case GNUTLS_MAC_SHA256: + target_kdf = 0x0001; + break; + case GNUTLS_MAC_SHA384: + target_kdf = 0x0002; + break; + default: + ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM); + goto error; + } + ret = _gnutls_buffer_append_prefix(&buf, 16, target_kdf); + if (ret < 0) { + goto error; + } + + ret = _gnutls_buffer_to_datum(&buf, imported_identity, 0); + if (ret < 0) { + goto error; + } + return 0; + +error: + _gnutls_buffer_clear(&buf); + return ret; +} + +static int derive_ipsk(const mac_entry_st *prf, + const gnutls_datum_t *imported_identity, + const gnutls_datum_t *epsk, uint8_t ipsk[MAX_HASH_SIZE]) +{ + uint8_t epskx[MAX_HASH_SIZE]; + uint8_t hashed_identity[MAX_HASH_SIZE]; + int ret; + + /* epskx = HKDF-Extract(0, epsk) */ + ret = _tls13_init_secret2(prf, epsk->data, epsk->size, epskx); + if (ret < 0) { + return ret; + } + ret = gnutls_hash_fast((gnutls_digest_algorithm_t)prf->id, + imported_identity->data, imported_identity->size, + hashed_identity); + if (ret < 0) { + return ret; + } + /* ipskx = HKDF-Expand-Label(epskx, "derived psk", Hash(ImportedIdentity), L) */ + return _tls13_expand_secret2(prf, DERIVED_PSK_LABEL, + sizeof(DERIVED_PSK_LABEL) - 1, + hashed_identity, prf->output_size, epskx, + prf->output_size, ipsk); +} + +/* This does the opposite of gnutls_psk_format_imported_identity. + * Note that this does not allocate memory, and the data field of + * identity and context must not be freed. + */ +static int parse_imported_identity(const gnutls_datum_t *imported_identity, + gnutls_datum_t *identity, + gnutls_datum_t *context, + gnutls_protocol_t *version, + gnutls_digest_algorithm_t *hash) +{ + uint16_t target_protocol; + uint16_t target_kdf; + gnutls_buffer_st buf; + size_t size; + int ret; + + _gnutls_ro_buffer_from_datum(&buf, (gnutls_datum_t *)imported_identity); + + /* external_identity */ + ret = _gnutls_buffer_pop_datum_prefix16(&buf, identity); + if (ret < 0) { + return ret; + } + + /* context */ + ret = _gnutls_buffer_pop_datum_prefix16(&buf, context); + if (ret < 0) { + return ret; + } + + /* target_protocol */ + ret = _gnutls_buffer_pop_prefix16(&buf, &size, 0); + if (ret < 0) { + return ret; + } + target_protocol = size; + *version = _gnutls_version_get((target_protocol >> 8) & 0xFF, + target_protocol & 0xFF); + + /* target_kdf */ + ret = _gnutls_buffer_pop_prefix16(&buf, &size, 0); + if (ret < 0) { + return ret; + } + target_kdf = size; + switch (target_kdf) { + case 0x0001: + *hash = GNUTLS_DIG_SHA256; + break; + case 0x0002: + *hash = GNUTLS_DIG_SHA384; + break; + default: + return gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM); + } + return 0; +} + static int client_send_params(gnutls_session_t session, gnutls_buffer_t extdata, const gnutls_psk_client_credentials_t cred) { @@ -282,11 +484,12 @@ static int client_send_params(gnutls_session_t session, gnutls_buffer_t extdata, psk_auth_info_t info = NULL; unsigned psk_id_len = 0; unsigned binders_len, binders_pos; + bool imported = false; tls13_ticket_st *ticket = &session->internals.tls13_ticket; if (((session->internals.flags & GNUTLS_NO_TICKETS) || session->internals.tls13_ticket.ticket.data == NULL) && - (!cred || !_gnutls_have_psk_credentials(cred, session))) { + (!cred || !have_psk_credentials(cred, session))) { return 0; } @@ -353,8 +556,9 @@ static int client_send_params(gnutls_session_t session, gnutls_buffer_t extdata, } ignore_ticket: - if (cred && _gnutls_have_psk_credentials(cred, session)) { + if (cred && have_psk_credentials(cred, session)) { gnutls_datum_t tkey; + gnutls_psk_key_flags flags; if (cred->binder_algo == NULL) { gnutls_assert(); @@ -366,7 +570,7 @@ ignore_ticket: prf_psk = cred->binder_algo; ret = _gnutls_find_psk_key(session, cred, &username, &tkey, - &free_username); + &flags, &free_username); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -390,6 +594,50 @@ ignore_ticket: user_key.size = tkey.size; } + if (flags & GNUTLS_PSK_KEY_EXT) { + uint8_t ipsk[MAX_HASH_SIZE]; + gnutls_datum_t imported_identity = { NULL, 0 }; + gnutls_datum_t context = { NULL, 0 }; + gnutls_protocol_t version; + gnutls_digest_algorithm_t hash; + const version_entry_st *vers; + + ret = parse_imported_identity(&username, + &imported_identity, + &context, &version, + &hash); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + vers = version_to_entry(version); + if (unlikely(!vers || !vers->tls13_sem)) { + gnutls_assert(); + goto cleanup; + } + if (hash != MAC_TO_DIG(prf_psk->id)) { + gnutls_assert(); + goto cleanup; + } + + ret = derive_ipsk(prf_psk, &username, &user_key, ipsk); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + _gnutls_free_datum(&user_key); + ret = _gnutls_set_datum(&user_key, ipsk, + prf_psk->output_size); + zeroize_key(ipsk, sizeof(ipsk)); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + imported = true; + } + ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1); if (ret < 0) { @@ -457,7 +705,8 @@ ignore_ticket: ret = compute_psk_binder(session, prf_res, binders_len, binders_pos, ext_offset, &rkey, - &client_hello, 1, binder_value); + &client_hello, BINDER_RES, + binder_value); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -498,7 +747,9 @@ ignore_ticket: ret = compute_psk_binder(session, prf_psk, binders_len, binders_pos, ext_offset, &user_key, - &client_hello, 0, binder_value); + &client_hello, + imported ? BINDER_IMP : BINDER_EXT, + binder_value); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -574,7 +825,7 @@ static int server_recv_params(gnutls_session_t session, /* These values should be set properly when session ticket is accepted. */ uint32_t ticket_age = UINT32_MAX; struct timespec ticket_creation_time = { 0, 0 }; - bool resuming; + enum binder_type binder_type; bool refuse_early_data = false; ret = _gnutls13_psk_ext_parser_init(&psk_parser, data, len); @@ -625,22 +876,69 @@ static int server_recv_params(gnutls_session_t session, tls13_ticket_deinit(&ticket_data); - resuming = 1; + binder_type = BINDER_RES; break; } else if (pskcred && psk.ob_ticket_age == 0 && psk.identity.size > 0 && psk.identity.size <= MAX_USERNAME_SIZE) { + gnutls_psk_key_flags flags; + uint8_t ipsk[MAX_HASH_SIZE]; + prf = pskcred->binder_algo; /* this fails only on configuration errors; as such we always * return its error code in that case */ ret = _gnutls_psk_pwd_find_entry( session, (char *)psk.identity.data, - psk.identity.size, &key); - if (ret < 0) + psk.identity.size, &key, &flags); + if (ret < 0) { return gnutls_assert_val(ret); + } + + if (flags & GNUTLS_PSK_KEY_EXT) { + gnutls_datum_t imported_identity = { NULL, 0 }; + gnutls_datum_t context = { NULL, 0 }; + gnutls_protocol_t version; + gnutls_digest_algorithm_t hash; + const version_entry_st *vers; - resuming = 0; + ret = parse_imported_identity( + &psk.identity, &imported_identity, + &context, &version, &hash); + if (ret < 0) { + gnutls_assert(); + goto fail; + } + + vers = version_to_entry(version); + if (unlikely(!vers || !vers->tls13_sem)) { + gnutls_assert(); + goto fail; + } + if (hash != MAC_TO_DIG(prf->id)) { + gnutls_assert(); + goto fail; + } + + ret = derive_ipsk(prf, &psk.identity, &key, + ipsk); + _gnutls_free_temp_key_datum(&key); + if (ret < 0) { + gnutls_assert(); + goto fail; + } + ret = _gnutls_set_datum(&key, ipsk, + prf->output_size); + zeroize_key(ipsk, sizeof(ipsk)); + if (ret < 0) { + gnutls_assert(); + goto fail; + } + + binder_type = BINDER_IMP; + } else { + binder_type = BINDER_EXT; + } break; } } @@ -667,7 +965,7 @@ static int server_recv_params(gnutls_session_t session, /* Compute the binder value for this PSK */ ret = compute_psk_binder(session, prf, psk_parser.binders_len + 2, 0, 0, - &key, &full_client_hello, resuming, + &key, &full_client_hello, binder_type, binder_value); if (ret < 0) { gnutls_assert(); @@ -691,7 +989,7 @@ static int server_recv_params(gnutls_session_t session, /* save the username in psk_auth_info to make it available * using gnutls_psk_server_get_username() */ - if (!resuming) { + if (binder_type != BINDER_RES) { assert(psk.identity.size <= MAX_USERNAME_SIZE); ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, @@ -760,10 +1058,12 @@ static int server_recv_params(gnutls_session_t session, /* Reference the selected pre-shared key */ session->key.binders[0].psk.data = key.data; session->key.binders[0].psk.size = key.size; + key.data = NULL; + key.size = 0; session->key.binders[0].idx = psk_index; session->key.binders[0].prf = prf; - session->key.binders[0].resumption = resuming; + session->key.binders[0].resumption = binder_type == BINDER_RES; ret = _gnutls_generate_early_secrets_for_psk(session); if (ret < 0) { @@ -771,10 +1071,8 @@ static int server_recv_params(gnutls_session_t session, goto fail; } - return 0; - fail: - gnutls_free(key.data); + _gnutls_free_datum(&key); return ret; } diff --git a/lib/ext/pre_shared_key.h b/lib/ext/pre_shared_key.h index 496d275a7f..f6a088c614 100644 --- a/lib/ext/pre_shared_key.h +++ b/lib/ext/pre_shared_key.h @@ -9,17 +9,6 @@ extern const hello_ext_entry_st ext_mod_pre_shared_key; -inline static unsigned -_gnutls_have_psk_credentials(const gnutls_psk_client_credentials_t cred, - gnutls_session_t session) -{ - if ((cred->get_function || cred->username.data) && - session->internals.priorities->have_psk) - return 1; - else - return 0; -} - int _gnutls_generate_early_secrets_for_psk(gnutls_session_t session); #endif /* GNUTLS_LIB_EXT_PRE_SHARED_KEY_H */ diff --git a/lib/handshake-defs.h b/lib/handshake-defs.h index 1b0c250e75..51aa5d2369 100644 --- a/lib/handshake-defs.h +++ b/lib/handshake-defs.h @@ -25,10 +25,12 @@ #define EARLY_TRAFFIC_LABEL "c e traffic" #define EXT_BINDER_LABEL "ext binder" #define RES_BINDER_LABEL "res binder" +#define IMP_BINDER_LABEL "imp binder" #define EARLY_EXPORTER_MASTER_LABEL "e exp master" #define HANDSHAKE_CLIENT_TRAFFIC_LABEL "c hs traffic" #define HANDSHAKE_SERVER_TRAFFIC_LABEL "s hs traffic" #define DERIVED_LABEL "derived" +#define DERIVED_PSK_LABEL "derived psk" #define APPLICATION_CLIENT_TRAFFIC_LABEL "c ap traffic" #define APPLICATION_SERVER_TRAFFIC_LABEL "s ap traffic" #define APPLICATION_TRAFFIC_UPDATE "traffic upd" diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index f4c003dcde..ec132cb5c3 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -2533,12 +2533,14 @@ typedef struct gnutls_psk_client_credentials_st *gnutls_psk_client_credentials_t * gnutls_psk_key_flags: * @GNUTLS_PSK_KEY_RAW: PSK-key in raw format. * @GNUTLS_PSK_KEY_HEX: PSK-key in hex format. + * @GNUTLS_PSK_KEY_EXT: PSK-key is external and to be imported. * * Enumeration of different PSK key flags. */ typedef enum gnutls_psk_key_flags { GNUTLS_PSK_KEY_RAW = 0, - GNUTLS_PSK_KEY_HEX + GNUTLS_PSK_KEY_HEX = 1 << 0, + GNUTLS_PSK_KEY_EXT = 1 << 1 } gnutls_psk_key_flags; void gnutls_psk_free_client_credentials(gnutls_psk_client_credentials_t sc); @@ -2570,12 +2572,24 @@ typedef int gnutls_psk_server_credentials_function(gnutls_session_t, gnutls_datum_t *key); typedef int gnutls_psk_server_credentials_function2( gnutls_session_t, const gnutls_datum_t *username, gnutls_datum_t *key); +typedef int gnutls_psk_server_credentials_function3( + gnutls_session_t, const gnutls_datum_t *username, gnutls_datum_t *key, + gnutls_psk_key_flags *flags); void gnutls_psk_set_server_credentials_function( gnutls_psk_server_credentials_t cred, gnutls_psk_server_credentials_function *func); void gnutls_psk_set_server_credentials_function2( gnutls_psk_server_credentials_t cred, gnutls_psk_server_credentials_function2 *func); +void gnutls_psk_set_server_credentials_function3( + gnutls_psk_server_credentials_t cred, + gnutls_psk_server_credentials_function3 *func); + +int gnutls_psk_format_imported_identity(const gnutls_datum_t *identity, + const gnutls_datum_t *context, + gnutls_protocol_t version, + gnutls_digest_algorithm_t hash, + gnutls_datum_t *imported_identity); typedef int gnutls_psk_client_credentials_function(gnutls_session_t, char **username, @@ -2583,12 +2597,18 @@ typedef int gnutls_psk_client_credentials_function(gnutls_session_t, typedef int gnutls_psk_client_credentials_function2(gnutls_session_t, gnutls_datum_t *username, gnutls_datum_t *key); +typedef int gnutls_psk_client_credentials_function3( + gnutls_session_t, gnutls_datum_t *username, gnutls_datum_t *key, + gnutls_psk_key_flags *flags); void gnutls_psk_set_client_credentials_function( gnutls_psk_client_credentials_t cred, gnutls_psk_client_credentials_function *func); void gnutls_psk_set_client_credentials_function2( gnutls_psk_client_credentials_t cred, gnutls_psk_client_credentials_function2 *func); +void gnutls_psk_set_client_credentials_function3( + gnutls_psk_client_credentials_t cred, + gnutls_psk_client_credentials_function3 *func); int gnutls_hex_encode(const gnutls_datum_t *data, char *result, size_t *result_size); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 72e425c3a0..fae2070dfc 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1409,6 +1409,16 @@ GNUTLS_3_7_7 *; } GNUTLS_3_7_5; +GNUTLS_3_8_1 +{ + global: + gnutls_psk_set_server_credentials_function3; + gnutls_psk_set_client_credentials_function3; + gnutls_psk_format_imported_identity; + local: + *; +} GNUTLS_3_7_7; + GNUTLS_FIPS140_3_4 { global: gnutls_cipher_self_test; @@ -280,9 +280,9 @@ int gnutls_psk_set_server_credentials_hint(gnutls_psk_server_credentials_t res, return 0; } -static int call_server_callback_legacy(gnutls_session_t session, - const gnutls_datum_t *username, - gnutls_datum_t *key) +static int call_server_callback1(gnutls_session_t session, + const gnutls_datum_t *username, + gnutls_datum_t *key) { gnutls_psk_server_credentials_t cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred( @@ -290,8 +290,29 @@ static int call_server_callback_legacy(gnutls_session_t session, if (unlikely(cred == NULL)) return gnutls_assert_val(-1); - return cred->pwd_callback_legacy(session, (const char *)username->data, - key); + return cred->pwd_callback1(session, (const char *)username->data, key); +} + +static int call_server_callback2(gnutls_session_t session, + const gnutls_datum_t *username, + gnutls_datum_t *key, + gnutls_psk_key_flags *flags) +{ + gnutls_psk_server_credentials_t cred; + int ret; + + cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred( + session, GNUTLS_CRD_PSK); + if (unlikely(cred == NULL)) + return gnutls_assert_val(-1); + + ret = cred->pwd_callback2(session, username, key); + if (ret >= 0) { + if (flags) { + *flags = 0; + } + } + return ret; } /** @@ -318,8 +339,9 @@ void gnutls_psk_set_server_credentials_function( gnutls_psk_server_credentials_t cred, gnutls_psk_server_credentials_function *func) { - cred->pwd_callback_legacy = func; - cred->pwd_callback = call_server_callback_legacy; + cred->pwd_callback1 = func; + cred->pwd_callback2 = call_server_callback1; + cred->pwd_callback = call_server_callback2; } /** @@ -349,31 +371,88 @@ void gnutls_psk_set_server_credentials_function2( gnutls_psk_server_credentials_t cred, gnutls_psk_server_credentials_function2 func) { + cred->pwd_callback1 = NULL; + cred->pwd_callback2 = func; + cred->pwd_callback = call_server_callback2; +} + +/** + * gnutls_psk_set_server_credentials_function3: + * @cred: is a #gnutls_psk_server_credentials_t type. + * @func: is the callback function + * + * This function can be used to set a callback to retrieve the user's PSK credentials. + * The callback's function form is: + * int (*callback)(gnutls_session_t, const gnutls_datum_t* username, + * gnutls_datum_t* key, gnutls_psk_key_flags *flags); + * + * This callback function has the same semantics as that of + * gnutls_psk_set_server_credentials_function2(), but it returns flags + * associated with the key. The callback may import external PSK + * using the method described in RFC 9258 by using + * gnutls_psk_format_imported_identity(). + * + * @username contains the actual username. + * The @key must be filled in using the gnutls_malloc(). + * + * In case the callback returned a negative number then gnutls will + * assume that the username does not exist. + * + * The callback function will only be called once per handshake. The + * callback function should return 0 on success, while -1 indicates + * an error. + **/ +void gnutls_psk_set_server_credentials_function3( + gnutls_psk_server_credentials_t cred, + gnutls_psk_server_credentials_function3 func) +{ + cred->pwd_callback1 = NULL; + cred->pwd_callback2 = NULL; cred->pwd_callback = func; - cred->pwd_callback_legacy = NULL; } -static int call_client_callback_legacy(gnutls_session_t session, - gnutls_datum_t *username, - gnutls_datum_t *key) +static int call_client_callback1(gnutls_session_t session, + gnutls_datum_t *username, gnutls_datum_t *key) { + gnutls_psk_client_credentials_t cred; int ret; char *user_p; - gnutls_psk_client_credentials_t cred = - (gnutls_psk_client_credentials_t)_gnutls_get_cred( - session, GNUTLS_CRD_PSK); + + cred = (gnutls_psk_client_credentials_t)_gnutls_get_cred( + session, GNUTLS_CRD_PSK); if (unlikely(cred == NULL)) return gnutls_assert_val(-1); - ret = cred->get_function_legacy(session, &user_p, key); + ret = cred->get_function1(session, &user_p, key); + if (ret >= 0) { + username->data = (uint8_t *)user_p; + username->size = strlen(user_p); + } + + return ret; +} + +static int call_client_callback2(gnutls_session_t session, + gnutls_datum_t *username, gnutls_datum_t *key, + gnutls_psk_key_flags *flags) +{ + gnutls_psk_client_credentials_t cred; + int ret; + + cred = (gnutls_psk_client_credentials_t)_gnutls_get_cred( + session, GNUTLS_CRD_PSK); + if (unlikely(cred == NULL)) + return gnutls_assert_val(-1); - if (ret) - goto end; + ret = cred->get_function2(session, username, key); + if (ret < 0) { + return ret; + } - username->data = (uint8_t *)user_p; - username->size = strlen(user_p); + if (flags) { + *flags = 0; + } -end: return ret; } @@ -402,8 +481,9 @@ void gnutls_psk_set_client_credentials_function( gnutls_psk_client_credentials_t cred, gnutls_psk_client_credentials_function *func) { - cred->get_function = call_client_callback_legacy; - cred->get_function_legacy = func; + cred->get_function1 = func; + cred->get_function2 = call_client_callback1; + cred->get_function = call_client_callback2; } /** @@ -434,8 +514,45 @@ void gnutls_psk_set_client_credentials_function2( gnutls_psk_client_credentials_t cred, gnutls_psk_client_credentials_function2 *func) { + cred->get_function1 = NULL; + cred->get_function2 = func; + cred->get_function = call_client_callback2; +} + +/** + * gnutls_psk_set_client_credentials_function3: + * @cred: is a #gnutls_psk_server_credentials_t type. + * @func: is the callback function + * + * This function can be used to set a callback to retrieve the username and + * password for client PSK authentication. + * The callback's function form is: + * int (*callback)(gnutls_session_t, gnutls_datum_t* username, + * gnutls_datum_t* key, gnutls_datum_t* context, gnutls_psk_key_flags *flags); + * + * This callback function has the same semantics as that of + * gnutls_psk_set_client_credentials_function2(), but it returns flags + * associated with the key. The callback may import external PSK + * using the method described in RFC 9258 by using + * gnutls_psk_format_imported_identity(). + * + * The data field of @username, @key, and @context must be allocated + * using gnutls_malloc(). The @username should be an ASCII string or + * UTF-8 string. In case of a UTF-8 string it is recommended to be + * following the PRECIS framework for usernames (rfc8265). + * + * The callback function will be called once per handshake. + * + * The callback function should return 0 on success. + * -1 indicates an error. + **/ +void gnutls_psk_set_client_credentials_function3( + gnutls_psk_client_credentials_t cred, + gnutls_psk_client_credentials_function3 *func) +{ + cred->get_function1 = NULL; + cred->get_function2 = NULL; cred->get_function = func; - cred->get_function_legacy = NULL; } /** |