/* Generates the PSK server key exchange * * struct { * select (KeyExchangeAlgorithm) { * // other cases for rsa, diffie_hellman, etc. * case psk: // NEW * uint8_t psk_identity_hint<0..2^16-1>; * }; * } ServerKeyExchange; * */ int _gnutls_gen_psk_server_kx (gnutls_session_t session, gnutls_buffer_st* data) { gnutls_psk_server_credentials_t cred; gnutls_datum_t hint; cred = (gnutls_psk_server_credentials_t) _gnutls_get_cred (session, GNUTLS_CRD_PSK, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* Abort sending this message if there is no PSK identity hint. */ if (cred->hint == NULL) { gnutls_assert (); return GNUTLS_E_INT_RET_0; } hint.data = (uint8_t*)cred->hint; hint.size = strlen (cred->hint); return _gnutls_buffer_append_data_prefix(data, 16, hint.data, hint.size); }
/* Generates the PSK client key exchange * * * struct { * select (KeyExchangeAlgorithm) { * uint8_t psk_identity<0..2^16-1>; * } exchange_keys; * } ClientKeyExchange; * */ int _gnutls_gen_psk_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { int ret, free; gnutls_datum_t username = {NULL, 0}; gnutls_datum_t key; gnutls_psk_client_credentials_t cred; psk_auth_info_t info; cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_PSK); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (info == NULL) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_set_psk_session_key(session, &key, NULL); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_data_prefix(data, 16, username.data, username.size); if (ret < 0) { gnutls_assert(); } if (username.size > sizeof(info->username)-1) { gnutls_assert(); ret = GNUTLS_E_ILLEGAL_SRP_USERNAME; goto cleanup; } assert(username.data != NULL); memcpy(info->username, username.data, username.size); info->username[username.size] = 0; cleanup: if (free) { gnutls_free(username.data); _gnutls_free_temp_key_datum(&key); } return ret; }
int _gnutls_gen_ecdh_common_client_kx_int (gnutls_session_t session, gnutls_buffer_st* data, gnutls_datum_t * psk_key) { int ret; gnutls_datum_t out; int curve = _gnutls_session_ecc_curve_get(session); /* generate temporal key */ ret = _gnutls_pk_generate(GNUTLS_PK_EC, curve, &session->key.ecdh_params); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_ecc_ansi_x963_export(curve, session->key.ecdh_params.params[6] /* x */, session->key.ecdh_params.params[7] /* y */, &out); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data_prefix(data, 8, out.data, out.size); _gnutls_free_datum(&out); if (ret < 0) return gnutls_assert_val(ret); /* generate pre-shared key */ ret = calc_ecdh_key(session, psk_key); if (ret < 0) return gnutls_assert_val(ret); return data->length; }
static int client_send(gnutls_session_t session, gnutls_buffer_st * extdata, status_request_ext_st * priv) { int ret_len = 1 + 2; int ret; size_t i; ret = _gnutls_buffer_append_prefix(extdata, 8, 1); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_prefix(extdata, 16, priv->responder_id_size); if (ret < 0) return gnutls_assert_val(ret); for (i = 0; i < priv->responder_id_size; i++) { if (priv->responder_id[i].size <= 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ret = _gnutls_buffer_append_data_prefix(extdata, 16, priv-> responder_id[i]. data, priv-> responder_id[i]. size); if (ret < 0) return gnutls_assert_val(ret); ret_len += 2 + priv->responder_id[i].size; } ret = _gnutls_buffer_append_data_prefix(extdata, 16, priv->request_extensions. data, priv->request_extensions. size); if (ret < 0) return gnutls_assert_val(ret); ret_len += 2 + priv->request_extensions.size; return ret_len; }
/* If the psk flag is set, then an empty psk_identity_hint will * be inserted */ int _gnutls_ecdh_common_print_server_kx(gnutls_session_t session, gnutls_buffer_st * data, gnutls_ecc_curve_t curve) { uint8_t p; int ret; gnutls_datum_t out; if (curve == GNUTLS_ECC_CURVE_INVALID) return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); /* just in case we are resuming a session */ gnutls_pk_params_release(&session->key.ecdh_params); gnutls_pk_params_init(&session->key.ecdh_params); /* curve type */ p = 3; ret = _gnutls_buffer_append_data(data, &p, 1); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_prefix(data, 16, _gnutls_ecc_curve_get_tls_id (curve)); if (ret < 0) return gnutls_assert_val(ret); /* generate temporal key */ ret = _gnutls_pk_generate_keys(GNUTLS_PK_EC, curve, &session->key.ecdh_params); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_ecc_ansi_x963_export(curve, session->key.ecdh_params. params[ECC_X] /* x */ , session->key.ecdh_params. params[ECC_Y] /* y */ , &out); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data_prefix(data, 8, out.data, out.size); _gnutls_free_datum(&out); if (ret < 0) return gnutls_assert_val(ret); return data->length; }
/* Generates the PSK client key exchange * * * struct { * select (KeyExchangeAlgorithm) { * uint8_t psk_identity<0..2^16-1>; * } exchange_keys; * } ClientKeyExchange; * */ int _gnutls_gen_psk_client_kx (gnutls_session_t session, gnutls_buffer_st* data) { int ret, free; gnutls_datum_t username; gnutls_datum_t key; gnutls_psk_client_credentials_t cred; cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred (session, GNUTLS_CRD_PSK, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } ret = _gnutls_find_psk_key( session, cred, &username, &key, &free); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_set_psk_session_key (session, &key, NULL); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_data_prefix(data, 16, username.data, username.size); if (ret < 0) { gnutls_assert(); } cleanup: if (free) { gnutls_free(username.data); gnutls_free(key.data); } return ret; }
int _gnutls_buffer_append_mpi (gnutls_buffer_st * buf, int pfx_size, bigint_t mpi, int lz) { gnutls_datum_t dd; int ret; if (lz) ret = _gnutls_mpi_dprint_lz (mpi, &dd); else ret = _gnutls_mpi_dprint (mpi, &dd); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data_prefix(buf, pfx_size, dd.data, dd.size); _gnutls_free_datum(&dd); return ret; }
static int gen_ecdhe_psk_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { int ret, free; gnutls_psk_client_credentials_t cred; gnutls_datum_t username, key; cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_PSK, NULL); if (cred == NULL) return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data_prefix(data, 16, username.data, username.size); if (ret < 0) { gnutls_assert(); goto cleanup; } /* The PSK key is set in there */ ret = _gnutls_gen_ecdh_common_client_kx_int(session, data, &key); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = data->length; cleanup: if (free) { _gnutls_free_datum(&username); _gnutls_free_datum(&key); } return ret; }
int _gnutls13_send_certificate(gnutls_session_t session, unsigned again) { int ret; gnutls_pcert_st *apr_cert_list = NULL; gnutls_privkey_t apr_pkey = NULL; int apr_cert_list_length = 0; mbuffer_st *bufel = NULL; gnutls_buffer_st buf; unsigned pos_mark, ext_pos_mark; unsigned i; struct ocsp_req_ctx_st ctx; gnutls_certificate_credentials_t cred; if (again == 0) { if (!session->internals.initial_negotiation_completed && session->internals.hsk_flags & HSK_PSK_SELECTED) return 0; if (session->security_parameters.entity == GNUTLS_SERVER && session->internals.resumed) return 0; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (session->security_parameters.entity == GNUTLS_CLIENT && !(session->internals.hsk_flags & HSK_CRT_ASKED)) { return 0; } ret = _gnutls_get_selected_cert(session, &apr_cert_list, &apr_cert_list_length, &apr_pkey); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_init_handshake_mbuffer(&buf); if (ret < 0) return gnutls_assert_val(ret); if (session->security_parameters.entity == GNUTLS_CLIENT) { ret = _gnutls_buffer_append_data_prefix(&buf, 8, session->internals.post_handshake_cr_context.data, session->internals.post_handshake_cr_context.size); if (ret < 0) { gnutls_assert(); goto cleanup; } } else { ret = _gnutls_buffer_append_prefix(&buf, 8, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } } /* mark total size */ pos_mark = buf.length; ret = _gnutls_buffer_append_prefix(&buf, 24, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } for (i=0;i<(unsigned)apr_cert_list_length;i++) { ret = _gnutls_buffer_append_data_prefix(&buf, 24, apr_cert_list[i].cert.data, apr_cert_list[i].cert.size); if (ret < 0) { gnutls_assert(); goto cleanup; } #ifdef ENABLE_OCSP if ((session->internals.selected_ocsp_length > 0 || session->internals.selected_ocsp_func) && _gnutls_hello_ext_is_present(session, GNUTLS_EXTENSION_STATUS_REQUEST)) { /* append status response if available */ ret = _gnutls_extv_append_init(&buf); if (ret < 0) { gnutls_assert(); goto cleanup; } ext_pos_mark = ret; ctx.pcert = &apr_cert_list[i]; ctx.cert_index = i; ctx.session = session; ctx.cred = cred; ret = _gnutls_extv_append(&buf, STATUS_REQUEST_TLS_ID, &ctx, append_status_request); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_extv_append_final(&buf, ext_pos_mark, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } } else #endif { ret = _gnutls_buffer_append_prefix(&buf, 16, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } } } _gnutls_write_uint24(buf.length-pos_mark-3, &buf.data[pos_mark]); bufel = _gnutls_buffer_to_mbuffer(&buf); } return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_PKT); cleanup: _gnutls_buffer_clear(&buf); return ret; }
static int append_status_request(void *_ctx, gnutls_buffer_st *buf) { struct ocsp_req_ctx_st *ctx = _ctx; gnutls_session_t session = ctx->session; int ret; gnutls_datum_t resp; unsigned free_resp = 0; assert(session->internals.selected_ocsp_func != NULL || session->internals.selected_ocsp_length != 0); /* The global ocsp callback function can only be used to return * a single certificate request */ if (session->internals.selected_ocsp_length == 1 && ctx->cert_index != 0) return 0; if (session->internals.selected_ocsp_length > 0) { if (ctx->cert_index < session->internals.selected_ocsp_length) { if ((session->internals.selected_ocsp[ctx->cert_index].exptime != 0 && gnutls_time(0) >= session->internals.selected_ocsp[ctx->cert_index].exptime) || session->internals.selected_ocsp[ctx->cert_index].response.data == NULL) { return 0; } resp.data = session->internals.selected_ocsp[ctx->cert_index].response.data; resp.size = session->internals.selected_ocsp[ctx->cert_index].response.size; ret = 0; } else { return 0; } } else if (session->internals.selected_ocsp_func) { if (ctx->cert_index == 0) { ret = session->internals.selected_ocsp_func(session, session->internals.selected_ocsp_func_ptr, &resp); free_resp = 1; } else { return 0; } } else return 0; if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) { return 0; } else if (ret < 0) { return gnutls_assert_val(ret); } ret = _gnutls_buffer_append_data(buf, "\x01", 1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: if (free_resp) gnutls_free(resp.data); return ret; }
static int _proxyinfo_send_params (gnutls_session_t session, gnutls_buffer_st* extdata) { //printf("Send params\n"); uint16_t len; unsigned i; int total_size = 0, ret; ProxyInfo_ext_st *priv; extension_priv_data_t epriv; ret = _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_PROXYINFO, &epriv); if (ret < 0) return 0; /* this function sends the client extension data (dnsname) */ if (session->security_parameters.entity == GNUTLS_CLIENT) { priv = epriv.ptr; if (priv->server_names_size == 0) return 0; /* uint16_t */ total_size = 2; total_size+=2; //2 byte for 16 bit integer proxy_count total_size+=(sizeof(gnutls_ProxyInfo_ext)/2)*((priv->proxy_cnt)+1); for (i = 0; i < priv->server_names_size; i++) { /* count the total size */ len = priv->server_names[i].name_length; /* uint8_t + uint16_t + size */ total_size += 1 + 2 + len; } /* UINT16: write total size of all names */ ret = _gnutls_buffer_append_prefix(extdata, 16, total_size - 2); ret = _gnutls_buffer_append_prefix(extdata, 16, priv->proxy_cnt); int count=priv->proxy_cnt; for(int proxy_id=0;proxy_id<count+1;proxy_id++){ ret = _gnutls_buffer_append_prefix(extdata, 16, priv->proxy_info[proxy_id].cipher_algo); ret = _gnutls_buffer_append_prefix(extdata, 16, priv->proxy_info[proxy_id].kx_algo); ret = _gnutls_buffer_append_prefix(extdata, 16, priv->proxy_info[proxy_id].mac_algo); ret = _gnutls_buffer_append_prefix(extdata, 16, priv->proxy_info[proxy_id].ip_addr); ret = _gnutls_buffer_append_prefix(extdata, 16, priv->proxy_info[proxy_id].mac_addr); } if (ret < 0) return gnutls_assert_val(ret); for (i = 0; i < priv->server_names_size; i++) { switch (priv->server_names[i].type) { case GNUTLS_NAME_DNS: len = priv->server_names[i].name_length; if (len == 0) break; /* UINT8: type of this extension * UINT16: size of the first name * LEN: the actual server name. */ ret = _gnutls_buffer_append_prefix(extdata, 8, 0); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data_prefix(extdata, 16, priv->server_names[i].name, len); if (ret < 0) return gnutls_assert_val(ret); break; default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } } } return total_size; }
static int gen_rsa_export_server_kx (gnutls_session_t session, gnutls_buffer_st* data) { gnutls_rsa_params_t rsa_params; const bigint_t *rsa_mpis; int ret = 0; gnutls_pcert_st *apr_cert_list; gnutls_privkey_t apr_pkey; int apr_cert_list_length; gnutls_datum_t signature, ddata; gnutls_certificate_credentials_t cred; gnutls_sign_algorithm_t sign_algo; unsigned int bits = 0; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } /* abort sending this message if we have a certificate * of 512 bits or less. */ gnutls_privkey_get_pk_algorithm (apr_pkey, &bits); if (apr_pkey && bits <= 512) { gnutls_assert (); return GNUTLS_E_INT_RET_0; } rsa_params = _gnutls_certificate_get_rsa_params (cred->rsa_params, cred->params_func, session); rsa_mpis = _gnutls_rsa_params_to_mpi (rsa_params); if (rsa_mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS; } if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE, sizeof (cert_auth_info_st), 0)) < 0) { gnutls_assert (); return ret; } _gnutls_rsa_export_set_pubkey (session, rsa_mpis[1], rsa_mpis[0]); ret = _gnutls_buffer_append_mpi( data, 16, rsa_mpis[0], 0); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_mpi( data, 16, rsa_mpis[1], 0); if (ret < 0) return gnutls_assert_val(ret); /* Generate the signature. */ ddata.data = data->data; ddata.size = data->length; if (apr_cert_list_length > 0) { if ((ret = _gnutls_handshake_sign_data (session, &apr_cert_list[0], apr_pkey, &ddata, &signature, &sign_algo)) < 0) { gnutls_assert (); return ret; } } else { gnutls_assert (); return data->length; /* do not put a signature - ILLEGAL! */ } ret = _gnutls_buffer_append_data_prefix( data, 16, signature.data, signature.size); _gnutls_free_datum (&signature); if (ret < 0) return gnutls_assert_val(ret); return data->length; }
static int gen_srp_cert_server_kx(gnutls_session_t session, gnutls_buffer_st * data) { ssize_t ret; gnutls_datum_t signature, ddata; gnutls_certificate_credentials_t cred; gnutls_pcert_st *apr_cert_list; gnutls_privkey_t apr_pkey; int apr_cert_list_length; gnutls_sign_algorithm_t sign_algo; const version_entry_st *ver = get_version(session); if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ret = _gnutls_gen_srp_server_kx(session, data); if (ret < 0) return ret; ddata.data = data->data; ddata.size = data->length; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert(session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert(); return ret; } if ((ret = _gnutls_handshake_sign_data(session, &apr_cert_list[0], apr_pkey, &ddata, &signature, &sign_algo)) < 0) { gnutls_assert(); return ret; } if (_gnutls_version_has_selectable_sighash(ver)) { const sign_algorithm_st *aid; uint8_t p[2]; if (sign_algo == GNUTLS_SIGN_UNKNOWN) { ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } aid = _gnutls_sign_to_tls_aid(sign_algo); if (aid == NULL) { gnutls_assert(); ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } p[0] = aid->hash_algorithm; p[1] = aid->sign_algorithm; ret = _gnutls_buffer_append_data(data, p, 2); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = _gnutls_buffer_append_data_prefix(data, 16, signature.data, signature.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = data->length; cleanup: _gnutls_free_datum(&signature); return ret; }
static int _gnutls_alpn_send_params (gnutls_session_t session, gnutls_buffer_st* extdata) { unsigned i; int total_size = 0, ret; alpn_ext_st *priv; extension_priv_data_t epriv; ret = _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_ALPN, &epriv); if (ret < 0) return 0; priv = epriv.ptr; if (priv->size == 0) return 0; if (session->security_parameters.entity == GNUTLS_SERVER) { if (priv->selected_protocol_size == 0) return 0; ret = _gnutls_buffer_append_prefix(extdata, 16, priv->selected_protocol_size+1); if (ret < 0) return gnutls_assert_val(ret); total_size += 2; ret = _gnutls_buffer_append_data_prefix(extdata, 8, priv->selected_protocol, priv->selected_protocol_size); if (ret < 0) return gnutls_assert_val(ret); total_size += 1+priv->selected_protocol_size; } else { int t = 0; for (i=0;i<priv->size;i++) t += priv->protocol_size[i] + 1; ret = _gnutls_buffer_append_prefix(extdata, 16, t); if (ret < 0) return gnutls_assert_val(ret); total_size += 2; for (i=0;i<priv->size;i++) { ret = _gnutls_buffer_append_data_prefix(extdata, 8, priv->protocols[i], priv->protocol_size[i]); if (ret < 0) return gnutls_assert_val(ret); total_size += 1+priv->protocol_size[i]; } } return total_size; }
static int gen_dhe_server_kx (gnutls_session_t session, gnutls_buffer_st* data) { bigint_t g, p; const bigint_t *mpis; int ret = 0, data_size; gnutls_pcert_st *apr_cert_list; gnutls_privkey_t apr_pkey; int apr_cert_list_length; gnutls_datum_t signature = { NULL, 0 }, ddata; gnutls_certificate_credentials_t cred; gnutls_dh_params_t dh_params; gnutls_sign_algorithm_t sign_algo; gnutls_protocol_t ver = gnutls_protocol_get_version (session); cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE, sizeof (cert_auth_info_st), 0)) < 0) { gnutls_assert (); return ret; } if (!_gnutls_session_is_ecc (session)) { dh_params = _gnutls_get_dh_params (cred->dh_params, cred->params_func, session); mpis = _gnutls_dh_params_to_mpi (dh_params); if (mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_DH_PARAMS; } p = mpis[0]; g = mpis[1]; _gnutls_dh_set_group (session, g, p); ret = _gnutls_dh_common_print_server_kx (session, g, p, dh_params->q_bits, data); } else { ret = _gnutls_ecdh_common_print_server_kx (session, data, _gnutls_session_ecc_curve_get(session)); } if (ret < 0) { gnutls_assert (); return ret; } data_size = ret; /* Generate the signature. */ ddata.data = data->data; ddata.size = data->length; if (apr_cert_list_length > 0) { if ((ret = _gnutls_handshake_sign_data (session, &apr_cert_list[0], apr_pkey, &ddata, &signature, &sign_algo)) < 0) { gnutls_assert (); goto cleanup; } } else { gnutls_assert (); ret = data_size; /* do not put a signature - ILLEGAL! */ goto cleanup; } if (_gnutls_version_has_selectable_sighash (ver)) { const sign_algorithm_st *aid; uint8_t p[2]; if (sign_algo == GNUTLS_SIGN_UNKNOWN) { ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } aid = _gnutls_sign_to_tls_aid (sign_algo); if (aid == NULL) { gnutls_assert(); ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } p[0] = aid->hash_algorithm; p[1] = aid->sign_algorithm; ret = _gnutls_buffer_append_data(data, p, 2); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = _gnutls_buffer_append_data_prefix(data, 16, signature.data, signature.size); if (ret < 0) { gnutls_assert(); } ret = data->length; cleanup: _gnutls_free_datum (&signature); return ret; }
static int _gnutls_server_cert_type_send_params(gnutls_session_t session, gnutls_buffer_st* data) { int ret; uint8_t cert_type; // Holds an IANA cert type ID uint8_t i = 0, num_cert_types = 0; priority_st* cert_priorities; gnutls_datum_t tmp_cert_types; // For type conversion uint8_t cert_types[GNUTLS_CRT_MAX]; // The list with supported cert types. Inv: 0 <= cert type Id < 256 /* Only activate this extension if we have cert credentials set * and alternative cert types are allowed */ if (!are_alternative_cert_types_allowed(session) || (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL)) return 0; if (!IS_SERVER(session)) { // Client mode // For brevity cert_priorities = &session->internals.priorities->server_ctype; /* Retrieve server certificate type priorities if any. If no * priorities are set then the default server certificate type * initialization values apply. This default is currently set to * X.509 in which case we don't enable this extension. */ if (cert_priorities->num_priorities > 0) { // Priorities are explicitly set /* If the certificate priority is explicitly set to only * X.509 (default) then, according to spec we don't send * this extension. We check this here to avoid further work in * this routine. We also check it below after pruning supported * types. */ if (cert_priorities->num_priorities == 1 && cert_priorities->priorities[0] == DEFAULT_CERT_TYPE) { _gnutls_handshake_log ("EXT[%p]: Server certificate type was set to default cert type (%s). " "We therefore do not send this extension.\n", session, gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE)); // Explicitly set but default ctype, so don't send anything return 0; } /* We are only allowed to send certificate types that we support. * Therefore we check this here and prune our original list. * This check might seem redundant now because we don't check for * credentials (they are not needed for a client) and only check the * priorities over which we already iterate. In the future, * additional checks might be necessary and they can be easily * added in the ..type_supported() routine without modifying the * structure of the code here. */ for (i = 0; i < cert_priorities->num_priorities; i++) { if (_gnutls_session_cert_type_supported (session, cert_priorities->priorities[i], false, GNUTLS_CTYPE_SERVER) == 0) { /* Check whether we are allowed to store another cert type * in our buffer. In other words, prevent a possible buffer * overflow. This situation can occur when a user sets * duplicate cert types in the priority strings. */ if (num_cert_types >= GNUTLS_CRT_MAX) return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); // Convert to IANA representation ret = cert_type2IANA(cert_priorities->priorities[i]); if (ret < 0) return gnutls_assert_val(ret); cert_type = ret; // For readability // Add this cert type to our list with supported types cert_types[num_cert_types] = cert_type; num_cert_types++; _gnutls_handshake_log ("EXT[%p]: Server certificate type %s (%d) was queued.\n", session, gnutls_certificate_type_get_name(cert_priorities->priorities[i]), cert_type); } } /* Check whether there are any supported certificate types left * after the previous pruning step. If not, we do not send this * extension. Also, if the only supported type is the default type * we do not send this extension (according to RFC7250). */ if (num_cert_types == 0) { // For now, this should not occur since we only check priorities while pruning. _gnutls_handshake_log ("EXT[%p]: Server certificate types were set but none of them is supported. " "We do not send this extension.\n", session); return 0; } else if (num_cert_types == 1 && IANA2cert_type(cert_types[0]) == DEFAULT_CERT_TYPE) { _gnutls_handshake_log ("EXT[%p]: The only supported server certificate type is (%s) which is the default. " "We therefore do not send this extension.\n", session, gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE)); return 0; } /* We have data to send and store a copy internally. We convert * our list with supported cert types to a datum_t in order to * be able to make the ..._set_datum call. */ tmp_cert_types.data = cert_types; tmp_cert_types.size = num_cert_types; _gnutls_hello_ext_set_datum(session, GNUTLS_EXTENSION_SERVER_CERT_TYPE, &tmp_cert_types); /* Serialize the certificate types into a sequence of octets * uint8: length of sequence of cert types (1 octet) * uint8: cert types (0 <= #octets <= 255) */ ret = _gnutls_buffer_append_data_prefix(data, 8, cert_types, num_cert_types); // Check for errors and cleanup in case of error if (ret < 0) { return gnutls_assert_val(ret); } else { // Number of bytes we are sending return num_cert_types + 1; } } } else { // Server mode // Retrieve negotiated server certificate type and send it ret = cert_type2IANA(get_certificate_type( session, GNUTLS_CTYPE_SERVER)); if (ret < 0) return gnutls_assert_val(ret); cert_type = ret; // For readability ret = gnutls_buffer_append_data(data, &cert_type, 1); if (ret < 0) return gnutls_assert_val(ret); return 1; // sent one byte } // In all other cases don't enable this extension return 0; }
/* Send the first key exchange message ( g, n, s) and append the verifier algorithm number * Data is allocated by the caller, and should have data_size size. */ int _gnutls_gen_srp_server_kx(gnutls_session_t session, gnutls_buffer_st * data) { int ret; char *username; SRP_PWD_ENTRY *pwd_entry; srp_server_auth_info_t info; size_t tmp_size; extension_priv_data_t epriv; srp_ext_st *priv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SRP, &epriv); if (ret < 0) { /* peer didn't send a username */ gnutls_assert(); return GNUTLS_E_UNKNOWN_SRP_USERNAME; } priv = epriv; if ((ret = _gnutls_auth_info_set(session, GNUTLS_CRD_SRP, sizeof(srp_server_auth_info_st), 1)) < 0) { gnutls_assert(); return ret; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_SRP); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); username = info->username; _gnutls_str_cpy(username, MAX_USERNAME_SIZE, priv->username); ret = _gnutls_srp_pwd_read_entry(session, username, &pwd_entry); if (ret < 0) { gnutls_assert(); return ret; } /* copy from pwd_entry to local variables (actually in session) */ tmp_size = pwd_entry->g.size; if (_gnutls_mpi_init_scan_nz(&G, pwd_entry->g.data, tmp_size) < 0) { gnutls_assert(); ret = GNUTLS_E_MPI_SCAN_FAILED; goto cleanup; } tmp_size = pwd_entry->n.size; if (_gnutls_mpi_init_scan_nz(&N, pwd_entry->n.data, tmp_size) < 0) { gnutls_assert(); ret = GNUTLS_E_MPI_SCAN_FAILED; goto cleanup; } tmp_size = pwd_entry->v.size; if (_gnutls_mpi_init_scan_nz(&V, pwd_entry->v.data, tmp_size) < 0) { gnutls_assert(); ret = GNUTLS_E_MPI_SCAN_FAILED; goto cleanup; } /* Calculate: B = (k*v + g^b) % N */ B = _gnutls_calc_srp_B(&_b, G, N, V); if (B == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } /* copy N (mod n) */ ret = _gnutls_buffer_append_data_prefix(data, 16, pwd_entry->n.data, pwd_entry->n.size); if (ret < 0) { gnutls_assert(); goto cleanup; } /* copy G (generator) to data */ ret = _gnutls_buffer_append_data_prefix(data, 16, pwd_entry->g.data, pwd_entry->g.size); if (ret < 0) { gnutls_assert(); goto cleanup; } /* copy the salt */ ret = _gnutls_buffer_append_data_prefix(data, 8, pwd_entry->salt.data, pwd_entry->salt.size); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Copy the B value */ ret = _gnutls_buffer_append_mpi(data, 16, B, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } _gnutls_mpi_log("SRP B: ", B); ret = data->length; cleanup: _gnutls_srp_entry_free(pwd_entry); return ret; }
/* Generate client key exchange message * * * struct { * select (KeyExchangeAlgorithm) { * uint8_t psk_identity<0..2^16-1>; * EncryptedPreMasterSecret; * } exchange_keys; * } ClientKeyExchange; */ static int _gnutls_gen_rsa_psk_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { cert_auth_info_t auth = session->key.auth_info; gnutls_datum_t sdata; /* data to send */ gnutls_pk_params_st params; gnutls_psk_client_credentials_t cred; gnutls_datum_t username, key; int ret, free; unsigned init_pos; if (auth == NULL) { /* this shouldn't have happened. The proc_certificate * function should have detected that. */ gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } gnutls_datum_t premaster_secret; premaster_secret.size = GNUTLS_MASTER_SIZE; premaster_secret.data = gnutls_malloc(premaster_secret.size); if (premaster_secret.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } /* Generate random */ ret = gnutls_rnd(GNUTLS_RND_RANDOM, premaster_secret.data, premaster_secret.size); if (ret < 0) { gnutls_assert(); return ret; } /* Set version */ if (session->internals.rsa_pms_version[0] == 0) { premaster_secret.data[0] = _gnutls_get_adv_version_major(session); premaster_secret.data[1] = _gnutls_get_adv_version_minor(session); } else { /* use the version provided */ premaster_secret.data[0] = session->internals.rsa_pms_version[0]; premaster_secret.data[1] = session->internals.rsa_pms_version[1]; } /* move RSA parameters to key (session). */ if ((ret = _gnutls_get_public_rsa_params(session, ¶ms)) < 0) { gnutls_assert(); return ret; } /* Encrypt premaster secret */ if ((ret = _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &premaster_secret, ¶ms)) < 0) { gnutls_assert(); return ret; } gnutls_pk_params_release(¶ms); cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_PSK); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); if (ret < 0) return gnutls_assert_val(ret); /* Here we set the PSK key */ ret = set_rsa_psk_session_key(session, &key, &premaster_secret); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Create message for client key exchange * * struct { * uint8_t psk_identity<0..2^16-1>; * EncryptedPreMasterSecret; * } */ init_pos = data->length; /* Write psk_identity and EncryptedPreMasterSecret into data stream */ ret = _gnutls_buffer_append_data_prefix(data, 16, username.data, username.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_data_prefix(data, 16, sdata.data, sdata.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = data->length - init_pos; cleanup: _gnutls_free_datum(&sdata); _gnutls_free_temp_key_datum(&premaster_secret); if (free) { _gnutls_free_temp_key_datum(&key); gnutls_free(username.data); } return ret; }
/* return RSA(random) using the peers public key */ int _gnutls_gen_rsa_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { cert_auth_info_t auth = session->key.auth_info; gnutls_datum_t sdata; /* data to send */ gnutls_pk_params_st params; int ret; if (auth == NULL) { /* this shouldn't have happened. The proc_certificate * function should have detected that. */ gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } session->key.key.size = GNUTLS_MASTER_SIZE; session->key.key.data = gnutls_malloc(session->key.key.size); if (session->key.key.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_rnd(GNUTLS_RND_RANDOM, session->key.key.data, session->key.key.size); if (ret < 0) { gnutls_assert(); return ret; } if (session->internals.rsa_pms_version[0] == 0) { session->key.key.data[0] = _gnutls_get_adv_version_major(session); session->key.key.data[1] = _gnutls_get_adv_version_minor(session); } else { /* use the version provided */ session->key.key.data[0] = session->internals.rsa_pms_version[0]; session->key.key.data[1] = session->internals.rsa_pms_version[1]; } /* move RSA parameters to key (session). */ if ((ret = _gnutls_get_public_rsa_params(session, ¶ms)) < 0) { gnutls_assert(); return ret; } ret = _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &session->key.key, ¶ms); gnutls_pk_params_release(¶ms); if (ret < 0) return gnutls_assert_val(ret); if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3.0 */ _gnutls_buffer_replace_data(data, &sdata); return data->length; } else { /* TLS 1 */ ret = _gnutls_buffer_append_data_prefix(data, 16, sdata.data, sdata.size); _gnutls_free_datum(&sdata); return ret; } }
static int _gnutls_srtp_send_params(gnutls_session_t session, gnutls_buffer_st * extdata) { unsigned i; int total_size = 0, ret; srtp_ext_st *priv; extension_priv_data_t epriv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SRTP, &epriv); if (ret < 0) return 0; priv = epriv; if (priv->profiles_size == 0) return 0; if (session->security_parameters.entity == GNUTLS_SERVER) { /* Don't send anything if no matching profile was found */ if (priv->selected_profile == 0) return 0; ret = _gnutls_buffer_append_prefix(extdata, 16, 2); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_prefix(extdata, 16, priv->selected_profile); if (ret < 0) return gnutls_assert_val(ret); total_size = 4; } else { ret = _gnutls_buffer_append_prefix(extdata, 16, 2 * priv->profiles_size); if (ret < 0) return gnutls_assert_val(ret); for (i = 0; i < priv->profiles_size; i++) { ret = _gnutls_buffer_append_prefix(extdata, 16, priv-> profiles[i]); if (ret < 0) return gnutls_assert_val(ret); } total_size = 2 + 2 * priv->profiles_size; } /* use_mki */ ret = _gnutls_buffer_append_data_prefix(extdata, 8, priv->mki, priv->mki_size); if (ret < 0) return gnutls_assert_val(ret); total_size += 1 + priv->mki_size; return total_size; }
int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned nr, unsigned again) { int ret = 0; mbuffer_st *bufel = NULL; gnutls_buffer_st buf; tls13_ticket_st ticket; unsigned i; /* Client does not send a NewSessionTicket */ if (unlikely(session->security_parameters.entity == GNUTLS_CLIENT)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* Session resumption has not been enabled */ if (session->internals.flags & GNUTLS_NO_TICKETS) return gnutls_assert_val(0); /* If we received the psk_key_exchange_modes extension which * does not have overlap with the server configuration, don't * send a session ticket */ if (session->internals.hsk_flags & HSK_PSK_KE_MODE_INVALID) return gnutls_assert_val(0); if (again == 0) { for (i=0;i<nr;i++) { unsigned init_pos; memset(&ticket, 0, sizeof(tls13_ticket_st)); bufel = NULL; ret = _gnutls_buffer_init_handshake_mbuffer(&buf); if (ret < 0) return gnutls_assert_val(ret); ret = generate_session_ticket(session, &ticket); if (ret < 0) { if (ret == GNUTLS_E_INT_RET_0) { ret = gnutls_assert_val(0); goto cleanup; } gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_prefix(&buf, 32, ticket.lifetime); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_prefix(&buf, 32, ticket.age_add); if (ret < 0) { gnutls_assert(); goto cleanup; } /* append ticket_nonce */ ret = _gnutls_buffer_append_data_prefix(&buf, 8, ticket.nonce, ticket.nonce_size); if (ret < 0) { gnutls_assert(); goto cleanup; } /* append ticket */ ret = _gnutls_buffer_append_data_prefix(&buf, 16, ticket.ticket.data, ticket.ticket.size); if (ret < 0) { gnutls_assert(); goto cleanup; } _gnutls_free_datum(&ticket.ticket); /* append extensions */ ret = _gnutls_extv_append_init(&buf); if (ret < 0) { gnutls_assert(); goto cleanup; } init_pos = ret; ret = _gnutls_extv_append(&buf, ext_mod_early_data.tls_id, session, (extv_append_func)append_nst_extension); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_extv_append_final(&buf, init_pos, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } bufel = _gnutls_buffer_to_mbuffer(&buf); ret = _gnutls_send_handshake2(session, bufel, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT; } } ret = _gnutls_handshake_io_write_flush(session); return ret; cleanup: _gnutls_free_datum(&ticket.ticket); _mbuffer_xfree(&bufel); _gnutls_buffer_clear(&buf); return ret; }
/* returns data_size or a negative number on failure */ static int _gnutls_server_name_send_params(gnutls_session_t session, gnutls_buffer_st * extdata) { uint16_t len; unsigned i; int total_size = 0, ret; server_name_ext_st *priv; extension_priv_data_t epriv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SERVER_NAME, &epriv); if (ret < 0) return 0; /* this function sends the client extension data (dnsname) */ if (session->security_parameters.entity == GNUTLS_CLIENT) { priv = epriv; if (priv->server_names_size == 0) return 0; /* uint16_t */ total_size = 2; for (i = 0; i < priv->server_names_size; i++) { /* count the total size */ len = priv->server_names[i].name_length; /* uint8_t + uint16_t + size */ total_size += 1 + 2 + len; } /* UINT16: write total size of all names */ ret = _gnutls_buffer_append_prefix(extdata, 16, total_size - 2); if (ret < 0) return gnutls_assert_val(ret); for (i = 0; i < priv->server_names_size; i++) { switch (priv->server_names[i].type) { case GNUTLS_NAME_DNS: len = priv->server_names[i].name_length; if (len == 0) break; /* UINT8: type of this extension * UINT16: size of the first name * LEN: the actual server name. */ ret = _gnutls_buffer_append_prefix(extdata, 8, 0); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data_prefix (extdata, 16, priv->server_names[i].name, len); if (ret < 0) return gnutls_assert_val(ret); break; default: gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } } } return total_size; }
static int client_send_params(gnutls_session_t session, gnutls_buffer_t extdata, const gnutls_psk_client_credentials_t cred) { int ret, ext_offset = 0; uint8_t binder_value[MAX_HASH_SIZE]; size_t spos; gnutls_datum_t username = {NULL, 0}; gnutls_datum_t user_key = {NULL, 0}, rkey = {NULL, 0}; gnutls_datum_t client_hello; unsigned next_idx; const mac_entry_st *prf_res = NULL; const mac_entry_st *prf_psk = NULL; struct timespec cur_time; uint32_t ticket_age, ob_ticket_age; int free_username = 0; psk_auth_info_t info = NULL; unsigned psk_id_len = 0; unsigned binders_len, binders_pos; if (((session->internals.flags & GNUTLS_NO_TICKETS) || session->internals.tls13_ticket.ticket.data == NULL) && (!cred || !_gnutls_have_psk_credentials(cred, session))) { return 0; } binders_len = 0; /* placeholder to be filled later */ spos = extdata->length; ret = _gnutls_buffer_append_prefix(extdata, 16, 0); if (ret < 0) return gnutls_assert_val(ret); /* First, let's see if we have a session ticket to send */ if (!(session->internals.flags & GNUTLS_NO_TICKETS) && session->internals.tls13_ticket.ticket.data != NULL) { /* We found a session ticket */ if (unlikely(session->internals.tls13_ticket.prf == NULL)) { _gnutls13_session_ticket_unset(session); ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); goto cleanup; } prf_res = session->internals.tls13_ticket.prf; gnutls_gettime(&cur_time); if (unlikely(_gnutls_timespec_cmp(&cur_time, &session->internals. tls13_ticket. arrival_time) < 0)) { gnutls_assert(); _gnutls13_session_ticket_unset(session); goto ignore_ticket; } /* Check whether the ticket is stale */ ticket_age = timespec_sub_ms(&cur_time, &session->internals.tls13_ticket. arrival_time); if (ticket_age / 1000 > session->internals.tls13_ticket.lifetime) { _gnutls13_session_ticket_unset(session); goto ignore_ticket; } ret = compute_psk_from_ticket(&session->internals.tls13_ticket, &rkey); if (ret < 0) { _gnutls13_session_ticket_unset(session); goto ignore_ticket; } /* Calculate obfuscated ticket age, in milliseconds, mod 2^32 */ ob_ticket_age = ticket_age + session->internals.tls13_ticket.age_add; if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16, session->internals.tls13_ticket.ticket.data, session->internals.tls13_ticket.ticket.size)) < 0) { gnutls_assert(); goto cleanup; } /* Now append the obfuscated ticket age */ if ((ret = _gnutls_buffer_append_prefix(extdata, 32, ob_ticket_age)) < 0) { gnutls_assert(); goto cleanup; } psk_id_len += 6 + session->internals.tls13_ticket.ticket.size; binders_len += 1 + _gnutls_mac_get_algo_len(prf_res); } ignore_ticket: if (cred && _gnutls_have_psk_credentials(cred, session)) { gnutls_datum_t tkey; if (cred->binder_algo == NULL) { gnutls_assert(); ret = gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); goto cleanup; } prf_psk = cred->binder_algo; ret = _gnutls_find_psk_key(session, cred, &username, &tkey, &free_username); if (ret < 0) { gnutls_assert(); goto cleanup; } if (username.size == 0 || username.size > UINT16_MAX) { ret = gnutls_assert_val(GNUTLS_E_INVALID_PASSWORD); goto cleanup; } if (!free_username) { /* we need to copy the key */ ret = _gnutls_set_datum(&user_key, tkey.data, tkey.size); if (ret < 0) { gnutls_assert(); goto cleanup; } } else { user_key.data = tkey.data; user_key.size = tkey.size; } ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1); if (ret < 0) { gnutls_assert(); goto cleanup; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); assert(info != NULL); memcpy(info->username, username.data, username.size); info->username[username.size] = 0; if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16, username.data, username.size)) < 0) { gnutls_assert(); goto cleanup; } /* Now append the obfuscated ticket age */ if ((ret = _gnutls_buffer_append_prefix(extdata, 32, 0)) < 0) { gnutls_assert(); goto cleanup; } psk_id_len += 6 + username.size; binders_len += 1 + _gnutls_mac_get_algo_len(prf_psk); } /* if no tickets or identities to be sent */ if (psk_id_len == 0) { /* reset extensions buffer */ extdata->length = spos; return 0; } _gnutls_write_uint16(psk_id_len, &extdata->data[spos]); binders_pos = extdata->length-spos; ext_offset = _gnutls_ext_get_extensions_offset(session); /* Compute the binders. extdata->data points to the start * of this client hello. */ assert(extdata->length >= sizeof(mbuffer_st)); assert(ext_offset >= (ssize_t)sizeof(mbuffer_st)); ext_offset -= sizeof(mbuffer_st); client_hello.data = extdata->data+sizeof(mbuffer_st); client_hello.size = extdata->length-sizeof(mbuffer_st); next_idx = 0; ret = _gnutls_buffer_append_prefix(extdata, 16, binders_len); if (ret < 0) { gnutls_assert_val(ret); goto cleanup; } if (prf_res && rkey.size > 0) { ret = compute_psk_binder(session, prf_res, binders_len, binders_pos, ext_offset, &rkey, &client_hello, 1, binder_value); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Associate the selected pre-shared key with the session */ gnutls_free(session->key.binders[next_idx].psk.data); session->key.binders[next_idx].psk.data = rkey.data; session->key.binders[next_idx].psk.size = rkey.size; rkey.data = NULL; session->key.binders[next_idx].prf = prf_res; session->key.binders[next_idx].resumption = 1; session->key.binders[next_idx].idx = next_idx; _gnutls_handshake_log("EXT[%p]: sent PSK resumption identity (%d)\n", session, next_idx); next_idx++; /* Add the binder */ ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_res->output_size); if (ret < 0) { gnutls_assert(); goto cleanup; } session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT; } if (prf_psk && user_key.size > 0 && info) { ret = compute_psk_binder(session, prf_psk, binders_len, binders_pos, ext_offset, &user_key, &client_hello, 0, binder_value); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Associate the selected pre-shared key with the session */ gnutls_free(session->key.binders[next_idx].psk.data); session->key.binders[next_idx].psk.data = user_key.data; session->key.binders[next_idx].psk.size = user_key.size; user_key.data = NULL; session->key.binders[next_idx].prf = prf_psk; session->key.binders[next_idx].resumption = 0; session->key.binders[next_idx].idx = next_idx; _gnutls_handshake_log("EXT[%p]: sent PSK identity '%s' (%d)\n", session, info->username, next_idx); next_idx++; /* Add the binder */ ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_psk->output_size); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: if (free_username) _gnutls_free_datum(&username); _gnutls_free_temp_key_datum(&user_key); _gnutls_free_temp_key_datum(&rkey); return ret; }