/** * gnutls_openpgp_crt_print: * @cert: The structure to be printed * @format: Indicate the format to use * @out: Newly allocated datum with (0) terminated string. * * This function will pretty print an OpenPGP certificate, suitable * for display to a human. * * The format should be (0) for future compatibility. * * The output @out needs to be deallocate using gnutls_free(). * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_crt_print(gnutls_openpgp_crt_t cert, gnutls_certificate_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; int ret; _gnutls_buffer_init(&str); if (format == GNUTLS_CRT_PRINT_ONELINE) print_oneline(&str, cert); else if (format == GNUTLS_CRT_PRINT_COMPACT) { print_oneline(&str, cert); _gnutls_buffer_append_data(&str, "\n", 1); print_key_fingerprint(&str, cert); } else { _gnutls_buffer_append_str(&str, _ ("OpenPGP Certificate Information:\n")); print_cert(&str, cert); } _gnutls_buffer_append_data(&str, "\0", 1); ret = _gnutls_buffer_to_datum(&str, out); if (out->size > 0) out->size--; return ret; }
/* returns data_size or a negative number on failure */ static int _gnutls_max_record_send_params (gnutls_session_t session, gnutls_buffer_st* extdata) { uint8_t p; int ret; /* this function sends the client extension data (dnsname) */ if (session->security_parameters.entity == GNUTLS_CLIENT) { extension_priv_data_t epriv; ret = _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_MAX_RECORD_SIZE, &epriv); if (ret < 0) /* it is ok not to have it */ { return 0; } if (epriv.num != DEFAULT_MAX_RECORD_SIZE) { p = (uint8_t) _gnutls_mre_record2num (epriv.num); ret = _gnutls_buffer_append_data( extdata, &p, 1); if (ret < 0) return gnutls_assert_val(ret); return 1; } } else { /* server side */ if (session->security_parameters.max_record_recv_size != DEFAULT_MAX_RECORD_SIZE) { p = (uint8_t) _gnutls_mre_record2num (session->security_parameters.max_record_recv_size); ret = _gnutls_buffer_append_data( extdata, &p, 1); if (ret < 0) return gnutls_assert_val(ret); return 1; } } return 0; }
/** * gnutls_openpgp_crt_print: * @cert: The structure to be printed * @format: Indicate the format to use * @out: Newly allocated datum with zero terminated string. * * This function will pretty print an OpenPGP certificate, suitable * for display to a human. * * The format should be zero for future compatibility. * * The output @out needs to be deallocate using gnutls_free(). * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_crt_print (gnutls_openpgp_crt_t cert, gnutls_certificate_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; _gnutls_buffer_init (&str); if (format == GNUTLS_CRT_PRINT_ONELINE) print_oneline (&str, cert); else { _gnutls_buffer_append_str (&str, _("OpenPGP Certificate Information:\n")); print_cert (&str, cert); } _gnutls_buffer_append_data (&str, "\0", 1); out->data = str.data; out->size = strlen (str.data); return 0; }
int _gnutls_buffer_append_prefix (gnutls_buffer_st * buf, int pfx_size, size_t data_size) { opaque ss[4]; if (pfx_size == 32) { _gnutls_write_uint32 (data_size, ss); pfx_size = 4; } else if (pfx_size == 24) { _gnutls_write_uint24 (data_size, ss); pfx_size = 3; } else if (pfx_size == 16) { _gnutls_write_uint16 (data_size, ss); pfx_size = 2; } else if (pfx_size == 8) { ss[0] = data_size; pfx_size = 1; } else return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); return _gnutls_buffer_append_data (buf, ss, pfx_size); }
static int gen_supplemental(gnutls_session_t session, const gnutls_supplemental_entry_st *supp, gnutls_buffer_st * buf) { int ret; gnutls_supp_send_func supp_send = supp->supp_send_func; size_t sizepos = buf->length; /* Make room for supplement type and length byte length field. */ ret = _gnutls_buffer_append_data(buf, "\0\0\0\0", 4); if (ret < 0) { gnutls_assert(); return ret; } ret = supp_send(session, buf); if (ret < 0) { gnutls_assert(); return ret; } /* If data were added, store type+length, otherwise reset. */ if (buf->length > sizepos + 4) { buf->data[sizepos] = (supp->type >> 8) & 0xFF; buf->data[sizepos + 1] = supp->type & 0xFF; buf->data[sizepos + 2] = ((buf->length - sizepos - 4) >> 8) & 0xFF; buf->data[sizepos + 3] = (buf->length - sizepos - 4) & 0xFF; } else
/** * gnutls_record_send: * @session: is a #gnutls_session_t structure. * @data: contains the data to send * @data_size: is the length of the data * * This function has the similar semantics with send(). The only * difference is that it accepts a GnuTLS session, and uses different * error codes. * Note that if the send buffer is full, send() will block this * function. See the send() documentation for more information. * * You can replace the default push function which is send(), by using * gnutls_transport_set_push_function(). * * If the EINTR is returned by the internal push function * then %GNUTLS_E_INTERRUPTED will be returned. If * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must * call this function again, with the exact same parameters; alternatively * you could provide a %NULL pointer for data, and 0 for * size. cf. gnutls_record_get_direction(). * * Note that in DTLS this function will return the %GNUTLS_E_LARGE_PACKET * error code if the send data exceed the data MTU value - as returned * by gnutls_dtls_get_data_mtu(). The errno value EMSGSIZE * also maps to %GNUTLS_E_LARGE_PACKET. * Note that since 3.2.13 this function can be called under cork in DTLS * mode, and will refuse to send data over the MTU size by returning * %GNUTLS_E_LARGE_PACKET. * * Returns: The number of bytes sent, or a negative error code. The * number of bytes sent might be less than @data_size. The maximum * number of bytes this function can send in a single call depends * on the negotiated maximum record size. **/ ssize_t gnutls_record_send(gnutls_session_t session, const void *data, size_t data_size) { if (session->internals.record_flush_mode == RECORD_FLUSH) { return _gnutls_send_int(session, GNUTLS_APPLICATION_DATA, -1, EPOCH_WRITE_CURRENT, data, data_size, MBUFFER_FLUSH); } else { /* GNUTLS_CORKED */ int ret; if (IS_DTLS(session)) { if (data_size + session->internals.record_presend_buffer.length > gnutls_dtls_get_data_mtu(session)) { return gnutls_assert_val(GNUTLS_E_LARGE_PACKET); } } ret = _gnutls_buffer_append_data(&session->internals. record_presend_buffer, data, data_size); if (ret < 0) return gnutls_assert_val(ret); return data_size; } }
/** * gnutls_ocsp_req_print: * @req: The structure to be printed * @format: Indicate the format to use * @out: Newly allocated datum with (0) terminated string. * * This function will pretty print a OCSP request, suitable for * display to a human. * * If the format is %GNUTLS_OCSP_PRINT_FULL then all fields of the * request will be output, on multiple lines. * * The output @out->data needs to be deallocate using gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_ocsp_req_print (gnutls_ocsp_req_t req, gnutls_ocsp_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; int rc; if (format != GNUTLS_OCSP_PRINT_FULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } _gnutls_buffer_init (&str); _gnutls_buffer_append_str (&str, _("OCSP Request Information:\n")); print_req (&str, req); _gnutls_buffer_append_data (&str, "\0", 1); rc = _gnutls_buffer_to_datum (&str, out); if (rc != GNUTLS_E_SUCCESS) { gnutls_assert (); return rc; } return GNUTLS_E_SUCCESS; }
/* Buffer for handshake packets. Keeps the packets in order * for finished messages to use them. Used in HMAC calculation * and finished messages. */ int _gnutls_handshake_hash_buffer_put (gnutls_session_t session, opaque * data, size_t length) { if (length == 0) return 0; if ((session->internals.max_handshake_data_buffer_size > 0) && ((length + session->internals.handshake_hash_buffer.length) > session->internals.max_handshake_data_buffer_size)) { gnutls_assert (); return GNUTLS_E_HANDSHAKE_TOO_LARGE; } _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data\n", (int) length); if (_gnutls_buffer_append_data (&session->internals.handshake_hash_buffer, data, length) < 0) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } return 0; }
/** * gnutls_ocsp_resp_print: * @resp: The structure to be printed * @format: Indicate the format to use * @out: Newly allocated datum with (0) terminated string. * * This function will pretty print a OCSP response, suitable for * display to a human. * * If the format is %GNUTLS_OCSP_PRINT_FULL then all fields of the * response will be output, on multiple lines. * * The output @out->data needs to be deallocate using gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_ocsp_resp_print (gnutls_ocsp_resp_t resp, gnutls_ocsp_print_formats_t format, gnutls_datum_t * out) { gnutls_buffer_st str; int rc; _gnutls_buffer_init (&str); _gnutls_buffer_append_str (&str, _("OCSP Response Information:\n")); print_resp (&str, resp, format); _gnutls_buffer_append_data (&str, "\0", 1); rc = _gnutls_buffer_to_datum (&str, out); if (rc != GNUTLS_E_SUCCESS) { gnutls_assert (); return rc; } return GNUTLS_E_SUCCESS; }
/* returns data_size or a negative number on failure */ static int _gnutls_signature_algorithm_send_params (gnutls_session_t session, gnutls_buffer_st* extdata) { int ret; size_t init_length = extdata->length; gnutls_protocol_t ver = gnutls_protocol_get_version (session); /* this function sends the client extension data */ if (session->security_parameters.entity == GNUTLS_CLIENT && _gnutls_version_has_selectable_sighash (ver)) { if (session->internals.priorities.sign_algo.algorithms > 0) { uint8_t p[MAX_SIGN_ALGO_SIZE]; ret = _gnutls_sign_algorithm_write_params (session, p, sizeof(p)); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data(extdata, p, ret); if (ret < 0) return gnutls_assert_val(ret); return extdata->length - init_length; } } /* if we are here it means we don't send the extension */ return 0; }
static int unescape_string(char *output, const char *input, size_t * size, char terminator) { gnutls_buffer_st str; int ret = 0; char *p; int len; _gnutls_buffer_init(&str); /* find terminator */ p = strchr(input, terminator); if (p != NULL) len = p - input; else len = strlen(input); ret = _gnutls_buffer_append_data(&str, input, len); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_buffer_unescape(&str); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_buffer_append_data(&str, "", 1); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_buffer_pop_data(&str, output, str.length); if (ret < 0) { gnutls_assert(); return ret; } _gnutls_buffer_clear(&str); return ret; }
/* 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; }
/* returns a positive number if we send the extension data, (0) if we do not want to send it, and a negative number on failure. */ static int session_ticket_send_params(gnutls_session_t session, gnutls_buffer_st * extdata) { session_ticket_ext_st *priv = NULL; extension_priv_data_t epriv; int ret; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SESSION_TICKET, &epriv); if (ret >= 0) priv = epriv; if (priv == NULL || !priv->session_ticket_enable) return 0; if (session->security_parameters.entity == GNUTLS_SERVER) { if (priv && priv->session_ticket_renew) { return GNUTLS_E_INT_RET_0; } } else { ret = _gnutls_ext_get_resumed_session_data(session, GNUTLS_EXTENSION_SESSION_TICKET, &epriv); if (ret >= 0) priv = epriv; /* no previous data. Just advertize it */ if (ret < 0) return GNUTLS_E_INT_RET_0; /* previous data had session tickets disabled. Don't advertize. Ignore. */ if (!priv->session_ticket_enable) return 0; if (priv->session_ticket_len > 0) { ret = _gnutls_buffer_append_data(extdata, priv-> session_ticket, priv-> session_ticket_len); if (ret < 0) return gnutls_assert_val(ret); return priv->session_ticket_len; } } return 0; }
int _gnutls_krb5_der_to_principal(const gnutls_datum_t * der, gnutls_datum_t * name) { int ret, result; ASN1_TYPE c2 = ASN1_TYPE_EMPTY; gnutls_buffer_st str; _gnutls_buffer_init(&str); result = asn1_create_element(_gnutls_get_gnutls_asn(), "GNUTLS.KRB5PrincipalName", &c2); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } result = asn1_der_decoding(&c2, der->data, der->size, NULL); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } ret = principal_to_str(c2, &str); if (ret < 0) { /* for some reason we cannot convert to a human readable string * the principal. Then we use the #HEX format. */ _gnutls_buffer_reset(&str); ret = _gnutls_buffer_append_data(&str, "#", 1); if (ret < 0) { gnutls_assert(); goto cleanup; } _gnutls_buffer_hexprint(&str, der->data, der->size); } asn1_delete_structure(&c2); return _gnutls_buffer_to_datum(&str, name, 1); cleanup: _gnutls_buffer_clear(&str); asn1_delete_structure(&c2); return ret; }
/* returns data_size or a negative number on failure */ static int _gnutls_supported_ecc_pf_send_params(gnutls_session_t session, gnutls_buffer_st * extdata) { const uint8_t p[2] = { 0x01, 0x00 }; /* only support uncompressed point format */ if (session->security_parameters.entity == GNUTLS_SERVER && !_gnutls_session_is_ecc(session)) return 0; if (session->internals.priorities.supported_ecc.algorithms > 0) { _gnutls_buffer_append_data(extdata, p, 2); return 2; } return 0; }
int _gnutls_buffer_append_data_prefix (gnutls_buffer_st * buf, int pfx_size, const void *data, size_t data_size) { int ret = 0, ret1; ret1 = _gnutls_buffer_append_prefix (buf, pfx_size, data_size); if (ret1 < 0) return gnutls_assert_val(ret1); if (data_size > 0) { ret = _gnutls_buffer_append_data (buf, data, data_size); if (ret < 0) return gnutls_assert_val(ret); } return ret + ret1; }
/** * gnutls_record_send: * @session: is a #gnutls_session_t structure. * @data: contains the data to send * @data_size: is the length of the data * * This function has the similar semantics with send(). The only * difference is that it accepts a GnuTLS session, and uses different * error codes. * Note that if the send buffer is full, send() will block this * function. See the send() documentation for full information. You * can replace the default push function by using * gnutls_transport_set_ptr2() with a call to send() with a * MSG_DONTWAIT flag if blocking is a problem. * If the EINTR is returned by the internal push function (the * default is send()) then %GNUTLS_E_INTERRUPTED will be returned. If * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must * call this function again, with the same parameters; alternatively * you could provide a %NULL pointer for data, and 0 for * size. cf. gnutls_record_get_direction(). * * Note that in DTLS this function will return the %GNUTLS_E_LARGE_PACKET * error code if the send data exceed the data MTU value - as returned * by gnutls_dtls_get_data_mtu(). The errno value EMSGSIZE * also maps to %GNUTLS_E_LARGE_PACKET. * * Returns: The number of bytes sent, or a negative error code. The * number of bytes sent might be less than @data_size. The maximum * number of bytes this function can send in a single call depends * on the negotiated maximum record size. **/ ssize_t gnutls_record_send (gnutls_session_t session, const void *data, size_t data_size) { if (session->internals.record_flush_mode == RECORD_FLUSH) { return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1, EPOCH_WRITE_CURRENT, data, data_size, MBUFFER_FLUSH); } else /* GNUTLS_CORKED */ { int ret; ret = _gnutls_buffer_append_data(&session->internals.record_presend_buffer, data, data_size); if (ret < 0) return gnutls_assert_val(ret); return data_size; } }
static int _gnutls_heartbeat_send_params(gnutls_session_t session, gnutls_buffer_st * extdata) { extension_priv_data_t epriv; uint8_t p; if (_gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_HEARTBEAT, &epriv) < 0) return 0; /* nothing to send - not enabled */ if (epriv.num & GNUTLS_HB_PEER_ALLOWED_TO_SEND) p = 1; else /*if (epriv.num & GNUTLS_HB_PEER_NOT_ALLOWED_TO_SEND) */ p = 2; if (_gnutls_buffer_append_data(extdata, &p, 1) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); return 1; }
/* returns data_size or a negative number on failure */ static int _gnutls_cert_type_send_params(gnutls_session_t session, gnutls_buffer_st * extdata) { unsigned len, i; int ret; uint8_t p; /* this function sends the client extension data (dnsname) */ if (session->security_parameters.entity == GNUTLS_CLIENT) { if (session->internals.priorities.cert_type.algorithms > 0) { len = session->internals.priorities.cert_type. algorithms; if (len == 1 && session->internals.priorities.cert_type. priority[0] == GNUTLS_CRT_X509) { /* We don't use this extension if X.509 certificates * are used. */ return 0; } /* this is a vector! */ p = (uint8_t) len; ret = _gnutls_buffer_append_data(extdata, &p, 1); if (ret < 0) return gnutls_assert_val(ret); for (i = 0; i < len; i++) { p = _gnutls_cert_type2num(session-> internals. priorities.cert_type. priority[i]); ret = _gnutls_buffer_append_data(extdata, &p, 1); if (ret < 0) return gnutls_assert_val(ret); } return len + 1; } } else { /* server side */ if (session->security_parameters.cert_type != DEFAULT_CERT_TYPE) { len = 1; p = _gnutls_cert_type2num(session-> security_parameters. cert_type); ret = _gnutls_buffer_append_data(extdata, &p, 1); if (ret < 0) return gnutls_assert_val(ret); return len; } } return 0; }
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 get_win_urls(const CERT_CONTEXT * cert, char **cert_url, char **key_url, char **label, gnutls_datum_t * der) { BOOL r; int ret; DWORD tl_size; gnutls_datum_t tmp_label = { NULL, 0 }; char name[MAX_CN * 2]; char hex[MAX_WID_SIZE * 2 + 1]; gnutls_buffer_st str; #ifdef WORDS_BIGENDIAN const unsigned bigendian = 1; #else const unsigned bigendian = 0; #endif if (cert == NULL) return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); if (der) { der->data = gnutls_malloc(cert->cbCertEncoded); if (der->data == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); memcpy(der->data, cert->pbCertEncoded, cert->cbCertEncoded); der->size = cert->cbCertEncoded; } _gnutls_buffer_init(&str); if (label) *label = NULL; if (key_url) *key_url = NULL; if (cert_url) *cert_url = NULL; tl_size = sizeof(name); r = CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, name, &tl_size); if (r != 0) { /* optional */ ret = _gnutls_ucs2_to_utf8(name, tl_size, &tmp_label, bigendian); if (ret < 0) { gnutls_assert(); goto fail; } if (label) *label = (char *)tmp_label.data; } tl_size = sizeof(name); r = CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, name, &tl_size); if (r == 0) { gnutls_assert(); ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto fail; } if (_gnutls_bin2hex(name, tl_size, hex, sizeof(hex), 0) == NULL) { ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); goto fail; } ret = _gnutls_buffer_append_printf(&str, WIN_URL "id=%s;type=cert", hex); if (ret < 0) { gnutls_assert(); goto fail; } if (tmp_label.data) { ret = _gnutls_buffer_append_str(&str, ";name="); if (ret < 0) { gnutls_assert(); goto fail; } ret = _gnutls_buffer_append_escape(&str, tmp_label.data, tmp_label.size, " "); if (ret < 0) { gnutls_assert(); goto fail; } } ret = _gnutls_buffer_append_data(&str, "\x00", 1); if (ret < 0) { gnutls_assert(); goto fail; } if (cert_url) *cert_url = (char *)str.data; _gnutls_buffer_init(&str); ret = _gnutls_buffer_append_printf(&str, WIN_URL "id=%s;type=privkey", hex); if (ret < 0) { gnutls_assert(); goto fail; } if (tmp_label.data) { ret = _gnutls_buffer_append_str(&str, ";name="); if (ret < 0) { gnutls_assert(); goto fail; } ret = _gnutls_buffer_append_escape(&str, tmp_label.data, tmp_label.size, " "); if (ret < 0) { gnutls_assert(); goto fail; } } ret = _gnutls_buffer_append_data(&str, "\x00", 1); if (ret < 0) { gnutls_assert(); goto fail; } if (key_url) *key_url = (char *)str.data; _gnutls_buffer_init(&str); ret = 0; goto cleanup; fail: if (der) gnutls_free(der->data); if (cert_url) gnutls_free(*cert_url); if (key_url) gnutls_free(*key_url); if (label) gnutls_free(*label); cleanup: _gnutls_buffer_clear(&str); return ret; }
/* This is a receive function for the gnutls handshake * protocol. Makes sure that we have received all data. */ static int parse_record_buffered_msgs (gnutls_session_t session, gnutls_handshake_description_t htype, handshake_buffer_st * hsk) { gnutls_datum_t msg; mbuffer_st* bufel = NULL, *prev = NULL; int ret; size_t data_size; handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg); if (bufel == NULL) return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; if (!IS_DTLS(session)) { ssize_t remain, append, header_size; do { if (bufel->type != GNUTLS_HANDSHAKE) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); /* if we have a half received message the complete it. */ remain = recv_buf[0].length - recv_buf[0].data.length; /* this is the rest of a previous message */ if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length > 0 && remain > 0) { if (msg.size <= remain) append = msg.size; else append = remain; ret = _gnutls_buffer_append_data(&recv_buf[0].data, msg.data, append); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_head_remove_bytes(&session->internals.record_buffer, append); } else /* received new message */ { ret = parse_handshake_header(session, bufel, htype, &recv_buf[0]); if (ret < 0) return gnutls_assert_val(ret); header_size = ret; session->internals.handshake_recv_buffer_size = 1; _mbuffer_set_uhead_size(bufel, header_size); data_size = MIN(recv_buf[0].length, _mbuffer_get_udata_size(bufel)); ret = _gnutls_buffer_append_data(&recv_buf[0].data, _mbuffer_get_udata_ptr(bufel), data_size); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_set_uhead_size(bufel, 0); _mbuffer_head_remove_bytes(&session->internals.record_buffer, data_size+header_size); if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) { /* an unexpected packet */ hsk->htype = recv_buf[0].htype; return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET); } } /* if packet is complete then return it */ if (recv_buf[0].length == recv_buf[0].data.length) { return get_last_packet(session, htype, hsk); } bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg); } while(bufel != NULL); /* if we are here it means that the received packets were not * enough to complete the handshake packet. */ return gnutls_assert_val(GNUTLS_E_AGAIN); } else /* DTLS */ { handshake_buffer_st tmp; do { /* we now * 0. parse headers * 1. insert to handshake_recv_buffer * 2. sort handshake_recv_buffer on sequence numbers * 3. return first packet if completed or GNUTLS_E_AGAIN. */ do { if (bufel->type != GNUTLS_HANDSHAKE) { gnutls_assert(); goto next; /* ignore packet */ } _gnutls_handshake_buffer_init(&tmp); ret = parse_handshake_header(session, bufel, htype, &tmp); if (ret < 0) { gnutls_assert(); _gnutls_audit_log("Invalid handshake packet headers. Discarding.\n"); break; } _mbuffer_consume(&session->internals.record_buffer, bufel, ret); data_size = MIN(tmp.length, tmp.end_offset-tmp.start_offset+1); ret = _gnutls_buffer_append_data(&tmp.data, _mbuffer_get_udata_ptr(bufel), data_size); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_consume(&session->internals.record_buffer, bufel, data_size); ret = merge_handshake_packet(session, &tmp); if (ret < 0) return gnutls_assert_val(ret); } while(_mbuffer_get_udata_size(bufel) > 0); prev = bufel; bufel = _mbuffer_dequeue(&session->internals.record_buffer, bufel); _mbuffer_xfree(&prev); continue; next: bufel = _mbuffer_head_get_next(bufel, NULL); } while(bufel != NULL); /* sort in descending order */ if (session->internals.handshake_recv_buffer_size > 1) qsort(recv_buf, session->internals.handshake_recv_buffer_size, sizeof(recv_buf[0]), handshake_compare); while(session->internals.handshake_recv_buffer_size > 0 && recv_buf[LAST_ELEMENT].sequence < session->internals.dtls.hsk_read_seq) { _gnutls_audit_log("Discarded replayed handshake packet with sequence %d\n", recv_buf[LAST_ELEMENT].sequence); _gnutls_handshake_buffer_clear(&recv_buf[LAST_ELEMENT]); session->internals.handshake_recv_buffer_size--; } return get_last_packet(session, htype, hsk); } }
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; }
/* Load session data from a buffer. */ int _gnutls_session_unpack (gnutls_session_t session, const gnutls_datum_t * packed_session) { int ret; gnutls_buffer_st sb; opaque id; _gnutls_buffer_init (&sb); if (packed_session == NULL || packed_session->size == 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_buffer_append_data (&sb, packed_session->data, packed_session->size); if (ret < 0) { gnutls_assert (); return ret; } if (_gnutls_get_auth_info (session) != NULL) { _gnutls_free_auth_info (session); } BUFFER_POP (&sb, &id, 1); switch (id) { #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: ret = unpack_srp_auth_info (session, &sb); if (ret < 0) { gnutls_assert (); goto error; } break; #endif #ifdef ENABLE_PSK case GNUTLS_CRD_PSK: ret = unpack_psk_auth_info (session, &sb); if (ret < 0) { gnutls_assert (); goto error; } break; #endif #ifdef ENABLE_ANON case GNUTLS_CRD_ANON: ret = unpack_anon_auth_info (session, &sb); if (ret < 0) { gnutls_assert (); return ret; } break; #endif case GNUTLS_CRD_CERTIFICATE: ret = unpack_certificate_auth_info (session, &sb); if (ret < 0) { gnutls_assert (); goto error; } break; default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto error; } /* Auth_info structures copied. Now copy security_parameters_st. * packed_session must have allocated space for the security parameters. */ ret = unpack_security_parameters (session, &sb); if (ret < 0) { gnutls_assert (); goto error; } ret = _gnutls_ext_unpack (session, &sb); if (ret < 0) { gnutls_assert (); goto error; } ret = 0; error: _gnutls_buffer_clear (&sb); return ret; }
static int principal_to_str(ASN1_TYPE c2, gnutls_buffer_st * str) { gnutls_datum_t realm = { NULL, 0 }; gnutls_datum_t component = { NULL, 0 }; unsigned char name_type[2]; int ret, result, len; unsigned i; char val[128]; ret = _gnutls_x509_read_value(c2, "realm", &realm); if (ret < 0) { gnutls_assert(); return ret; } len = sizeof(name_type); result = asn1_read_value(c2, "principalName.name-type", name_type, &len); if (result != ASN1_SUCCESS) { gnutls_assert(); ret = _gnutls_asn2err(result); goto cleanup; } if (len != 1 || (name_type[0] != 1 && name_type[0] != 2 && name_type[0] != 10)) { ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } for (i = 0;; i++) { snprintf(val, sizeof(val), "principalName.name-string.?%u", i + 1); ret = _gnutls_x509_read_value(c2, val, &component); if (ret == GNUTLS_E_ASN1_VALUE_NOT_FOUND || ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) break; if (ret < 0) { gnutls_assert(); goto cleanup; } if (i > 0) { ret = _gnutls_buffer_append_data(str, "/", 1); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = _gnutls_buffer_append_data(str, component.data, component.size); if (ret < 0) { gnutls_assert(); goto cleanup; } _gnutls_free_datum(&component); } ret = _gnutls_buffer_append_data(str, "@", 1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_buffer_append_data(str, realm.data, realm.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; cleanup: _gnutls_free_datum(&component); gnutls_free(realm.data); return ret; }
int _gnutls_buffer_append_str (gnutls_buffer_st * dest, const char *src) { return _gnutls_buffer_append_data (dest, src, strlen (src)); }
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; }
/* This is a receive function for the gnutls handshake * protocol. Makes sure that we have received all data. * * htype is the next handshake packet expected. */ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session) { gnutls_datum_t msg; mbuffer_st *bufel = NULL, *prev = NULL; int ret; size_t data_size; handshake_buffer_st *recv_buf = session->internals.handshake_recv_buffer; bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg); if (bufel == NULL) return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; if (!IS_DTLS(session)) { ssize_t append, header_size; do { if (bufel->type != GNUTLS_HANDSHAKE) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET); if (unlikely (session->internals.handshake_recv_buffer_size == 0 && msg.size < HANDSHAKE_HEADER_SIZE(session) && session->internals.handshake_header_recv_buffer.byte_length < HANDSHAKE_HEADER_SIZE(session) - msg.size)) { bufel = _mbuffer_head_pop_first(&session->internals.record_buffer); _mbuffer_enqueue(&session->internals.handshake_header_recv_buffer, bufel); break; } else if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length > recv_buf[0].data.length) { /* this is the rest of a previous message */ append = MIN(msg.size, recv_buf[0].length - recv_buf[0].data.length); ret = _gnutls_buffer_append_data(&recv_buf [0].data, msg.data, append); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_head_remove_bytes(&session-> internals. record_buffer, append); } else { /* received new message */ if (unlikely (session->internals. handshake_header_recv_buffer.length > 0)) { bufel = _mbuffer_head_pop_first(&session->internals. record_buffer); _mbuffer_enqueue(&session->internals. handshake_header_recv_buffer, bufel); ret = _mbuffer_linearize_align16(&session->internals. handshake_header_recv_buffer, get_total_headers(session)); if (ret < 0) return gnutls_assert_val(ret); bufel = _mbuffer_head_pop_first(&session->internals. handshake_header_recv_buffer); _mbuffer_head_push_first(&session->internals. record_buffer, bufel); } ret = parse_handshake_header(session, bufel, &recv_buf[0]); if (ret < 0) return gnutls_assert_val(ret); header_size = ret; session->internals. handshake_recv_buffer_size = 1; _mbuffer_set_uhead_size(bufel, header_size); data_size = MIN(recv_buf[0].length, _mbuffer_get_udata_size(bufel)); ret = _gnutls_buffer_append_data(&recv_buf [0].data, _mbuffer_get_udata_ptr (bufel), data_size); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_set_uhead_size(bufel, 0); _mbuffer_head_remove_bytes(&session-> internals. record_buffer, data_size + header_size); } /* if packet is complete then return it */ if (recv_buf[0].length == recv_buf[0].data.length) { return 0; } bufel = _mbuffer_head_get_first(&session->internals. record_buffer, &msg); } while (bufel != NULL); /* if we are here it means that the received packets were not * enough to complete the handshake packet. */ return gnutls_assert_val(GNUTLS_E_AGAIN); } else { /* DTLS */ handshake_buffer_st tmp; do { /* we now * 0. parse headers * 1. insert to handshake_recv_buffer * 2. sort handshake_recv_buffer on sequence numbers * 3. return first packet if completed or GNUTLS_E_AGAIN. */ do { if (bufel->type != GNUTLS_HANDSHAKE) { gnutls_assert(); goto next; /* ignore packet */ } _gnutls_handshake_buffer_init(&tmp); ret = parse_handshake_header(session, bufel, &tmp); if (ret < 0) { gnutls_assert(); _gnutls_audit_log(session, "Invalid handshake packet headers. Discarding.\n"); break; } _mbuffer_consume(&session->internals. record_buffer, bufel, ret); data_size = MIN(tmp.length, tmp.end_offset - tmp.start_offset + 1); ret = _gnutls_buffer_append_data(&tmp.data, _mbuffer_get_udata_ptr (bufel), data_size); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_consume(&session->internals. record_buffer, bufel, data_size); ret = merge_handshake_packet(session, &tmp); if (ret < 0) return gnutls_assert_val(ret); } while (_mbuffer_get_udata_size(bufel) > 0); prev = bufel; bufel = _mbuffer_dequeue(&session->internals. record_buffer, bufel); _mbuffer_xfree(&prev); continue; next: bufel = _mbuffer_head_get_next(bufel, NULL); } while (bufel != NULL); /* sort in descending order */ if (session->internals.handshake_recv_buffer_size > 1) qsort(recv_buf, session->internals. handshake_recv_buffer_size, sizeof(recv_buf[0]), handshake_compare); while (session->internals.handshake_recv_buffer_size > 0 && recv_buf[LAST_ELEMENT].sequence < session->internals.dtls.hsk_read_seq) { _gnutls_audit_log(session, "Discarded replayed handshake packet with sequence %d\n", recv_buf[LAST_ELEMENT].sequence); _gnutls_handshake_buffer_clear(&recv_buf [LAST_ELEMENT]); session->internals.handshake_recv_buffer_size--; } return 0; } }
static int _gnutls_sr_send_params (gnutls_session_t session, gnutls_buffer_st* extdata) { /* The format of this extension is a one-byte length of verify data followed * by the verify data itself. Note that the length byte does not include * itself; IOW, empty verify data is represented as a length of 0. That means * the minimum extension is one byte: 0x00. */ sr_ext_st *priv; int ret, set = 0, len; extension_priv_data_t epriv; size_t init_length = extdata->length; if (session->internals.priorities.sr == SR_DISABLED) { gnutls_assert (); return 0; } ret = _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv); if (ret < 0) { set = 1; } if (set != 0) { priv = gnutls_calloc (1, sizeof (*priv)); if (priv == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } epriv.ptr = priv; _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv); } else priv = epriv.ptr; /* Always offer the extension if we're a client */ if (priv->connection_using_safe_renegotiation || session->security_parameters.entity == GNUTLS_CLIENT) { len = priv->client_verify_data_len; if (session->security_parameters.entity == GNUTLS_SERVER) len += priv->server_verify_data_len; ret = _gnutls_buffer_append_prefix(extdata, 8, len); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_buffer_append_data(extdata, priv->client_verify_data, priv->client_verify_data_len); if (ret < 0) return gnutls_assert_val(ret); if (session->security_parameters.entity == GNUTLS_SERVER) { ret = _gnutls_buffer_append_data(extdata, priv->server_verify_data, priv->server_verify_data_len); if (ret < 0) return gnutls_assert_val(ret); } } else return 0; return extdata->length - init_length; }