int _gnutls_gen_extensions (gnutls_session_t session, opaque * data, size_t data_size) { int size; uint16_t pos = 0; opaque *sdata; int sdata_size; size_t i; if (data_size < 2) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* allocate enough data for each extension. */ sdata_size = data_size; sdata = gnutls_malloc (sdata_size); if (sdata == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } pos += 2; for (i = 0; i < extfunc_size; i++) { gnutls_extension_entry *p = &extfunc[i]; if (p->send_func == NULL) continue; size = p->send_func (session, sdata, sdata_size); if (size > 0) { if (data_size < pos + (size_t) size + 4) { gnutls_assert (); gnutls_free (sdata); return GNUTLS_E_INTERNAL_ERROR; } /* write extension type */ _gnutls_write_uint16 (p->type, &data[pos]); pos += 2; /* write size */ _gnutls_write_uint16 (size, &data[pos]); pos += 2; memcpy (&data[pos], sdata, size); pos += size; /* add this extension to the extension list */ _gnutls_extension_list_add (session, p->type); _gnutls_debug_log ("EXT[%p]: Sending extension %s\n", session, p->name); } else if (size < 0) { gnutls_assert (); gnutls_free (sdata); return size; } } size = pos; pos -= 2; /* remove the size of the size header! */ _gnutls_write_uint16 (pos, data); if (size == 2) { /* empty */ size = 0; } gnutls_free (sdata); return size; }
int _gnutls_gen_extensions(gnutls_session_t session, gnutls_buffer_st * extdata, gnutls_ext_parse_type_t parse_type) { int size; int pos, size_pos, ret; size_t i, init_size = extdata->length; pos = extdata->length; /* we will store length later on */ ret = _gnutls_buffer_append_prefix(extdata, 16, 0); if (ret < 0) return gnutls_assert_val(ret); for (i = 0; i < extfunc_size; i++) { extension_entry_st *p = &extfunc[i]; if (p->send_func == NULL) continue; if (parse_type != GNUTLS_EXT_ANY && p->parse_type != parse_type) continue; ret = _gnutls_buffer_append_prefix(extdata, 16, p->type); if (ret < 0) return gnutls_assert_val(ret); size_pos = extdata->length; ret = _gnutls_buffer_append_prefix(extdata, 16, 0); if (ret < 0) return gnutls_assert_val(ret); size = p->send_func(session, extdata); /* returning GNUTLS_E_INT_RET_0 means to send an empty * extension of this type. */ if (size > 0 || size == GNUTLS_E_INT_RET_0) { if (size == GNUTLS_E_INT_RET_0) size = 0; /* write the real size */ _gnutls_write_uint16(size, &extdata->data[size_pos]); /* add this extension to the extension list */ _gnutls_extension_list_add(session, p->type); _gnutls_handshake_log ("EXT[%p]: Sending extension %s (%d bytes)\n", session, p->name, size); } else if (size < 0) { gnutls_assert(); return size; } else if (size == 0) extdata->length -= 4; /* reset type and size */ } /* remove any initial data, and the size of the header */ size = extdata->length - init_size - 2; if (size > 0) _gnutls_write_uint16(size, &extdata->data[pos]); else if (size == 0) extdata->length -= 2; /* the length bytes */ return size; }
int _gnutls_parse_extensions(gnutls_session_t session, gnutls_ext_parse_type_t parse_type, const uint8_t * data, int data_size) { int next, ret; int pos = 0; uint16_t type; const uint8_t *sdata; gnutls_ext_recv_func ext_recv; uint16_t size; #ifdef DEBUG int i; if (session->security_parameters.entity == GNUTLS_CLIENT) for (i = 0; i < session->internals.extensions_sent_size; i++) { _gnutls_handshake_log ("EXT[%d]: expecting extension '%s'\n", session, _gnutls_extension_get_name(session->internals. extensions_sent [i])); } #endif DECR_LENGTH_RET(data_size, 2, 0); next = _gnutls_read_uint16(data); pos += 2; DECR_LENGTH_RET(data_size, next, 0); do { DECR_LENGTH_RET(next, 2, 0); type = _gnutls_read_uint16(&data[pos]); pos += 2; if (session->security_parameters.entity == GNUTLS_CLIENT) { if ((ret = _gnutls_extension_list_check(session, type)) < 0) { gnutls_assert(); return ret; } } else { _gnutls_extension_list_add(session, type); } DECR_LENGTH_RET(next, 2, 0); size = _gnutls_read_uint16(&data[pos]); pos += 2; DECR_LENGTH_RET(next, size, 0); sdata = &data[pos]; pos += size; ext_recv = _gnutls_ext_func_recv(type, parse_type); if (ext_recv == NULL) { _gnutls_handshake_log ("EXT[%p]: Found extension '%s/%d'\n", session, _gnutls_extension_get_name(type), type); continue; } _gnutls_handshake_log ("EXT[%p]: Parsing extension '%s/%d' (%d bytes)\n", session, _gnutls_extension_get_name(type), type, size); if ((ret = ext_recv(session, sdata, size)) < 0) { gnutls_assert(); return ret; } } while (next > 2); return 0; }