static void handle_conn(Broker *broker, HttpRequest *req, Socket *sock) { json_error_t err; json_t *body; { const char *start = strchr(req->body, '{'); const char *end = strrchr(req->body, '}'); if (!(start && end)) { goto exit; } body = json_loadb(start, end - start + 1, 0, &err); if (!body) { broker_send_internal_error(sock); goto exit; } } const char *dsId = broker_http_param_get(&req->uri, "dsId"); if (!dsId) { goto exit; } log_info("%s connecting \n", dsId); const char *token = broker_http_param_get(&req->uri, "token"); json_t *resp = broker_handshake_handle_conn(broker, dsId, token, body); json_decref(body); if (!resp) { broker_send_internal_error(sock); goto exit; } char *data = json_dumps(resp, JSON_INDENT(2)); json_decref(resp); if (!data) { broker_send_internal_error(sock); goto exit; } char buf[1024]; int len = snprintf(buf, sizeof(buf) - 1, CONN_RESP, (int) strlen(data), data); buf[len] = '\0'; dslink_free(data); dslink_socket_write(sock, buf, (size_t) len); exit: return; }
static ssize_t want_write_cb(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) { (void) flags; DSLink *link = user_data; int written = dslink_socket_write(link->_socket, (char *) data, len); if (written < 0) { if (errno == MBEDTLS_ERR_SSL_WANT_WRITE) { wslay_event_set_error(ctx, WSLAY_ERR_WANT_WRITE); } else { wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE); } return -1; } return written; }
int dslink_handshake_connect_ws(Url *url, mbedtls_ecdh_context *key, const char *uri, const char *tempKey, const char *salt, const char *dsId, Socket **sock) { *sock = NULL; int ret = 0; unsigned char auth[90]; if ((ret = gen_auth_key(key, tempKey, salt, auth, sizeof(auth))) != 0) { goto exit; } char req[512]; size_t reqLen; { char builtUri[256]; snprintf(builtUri, sizeof(builtUri) - 1, "%s?auth=%s&dsId=%s", uri, auth, dsId); char wsKey[32]; if ((ret = gen_ws_key(wsKey, sizeof(wsKey))) != 0) { goto exit; } reqLen = snprintf(req, sizeof(req), DSLINK_WS_REQ, builtUri, url->host, url->port, wsKey); } if ((ret = dslink_socket_connect(sock, url->host, url->port, url->secure)) != 0) { *sock = NULL; goto exit; } dslink_socket_write(*sock, req, reqLen); char buf[1024]; size_t len = 0; memset(buf, 0, sizeof(buf)); while (len < (sizeof(buf) - 1)) { // Read 1 byte at a time to ensure that we don't accidentally // read web socket data int read = dslink_socket_read(*sock, buf + len, 1); if (read <= 0) { goto exit; } if (buf[len++] == '\n' && strstr(buf, "\r\n\r\n")) { if (!strstr(buf, "101 Switching Protocols")) { ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; } if (strstr(buf, "401 Unauthorized")) { ret = DSLINK_HANDSHAKE_UNAUTHORIZED; } goto exit; } } // Failed to find the end of the HTTP response ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; exit: if (ret != 0 && *sock) { dslink_socket_close(*sock); *sock = NULL; } return ret; }
int dslink_handshake_generate(Url *url, mbedtls_ecdh_context *key, const char *name, uint8_t isRequester, uint8_t isResponder, json_t **handshake, char **dsId) { *handshake = NULL; Socket *sock = NULL; char *resp = NULL; char *body = NULL; int ret = 0; unsigned char pubKeyBin[65]; size_t pubKeyBinLen = 0; unsigned char pubKey[90]; size_t pubKeyLen = 0; if ((errno = mbedtls_ecp_point_write_binary(&key->grp, &key->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &pubKeyBinLen, pubKeyBin, sizeof(pubKeyBin))) != 0) { ret = DSLINK_CRYPT_KEY_ENCODE_ERR; goto exit; } if ((errno = dslink_base64_url_encode(pubKey, sizeof(pubKey), &pubKeyLen, pubKeyBin, pubKeyBinLen)) != 0) { ret = DSLINK_CRYPT_BASE64_URL_ENCODE_ERR; goto exit; } { // Generate dsId unsigned char sha[32]; mbedtls_sha256(pubKeyBin, pubKeyBinLen, sha, 0); unsigned char tmp[45]; size_t tmpLen = 0; if ((errno = dslink_base64_url_encode((unsigned char *) tmp, sizeof(tmp), &tmpLen, sha, sizeof(sha))) != 0) { ret = DSLINK_CRYPT_BASE64_URL_ENCODE_ERR; goto exit; } size_t nameLen = strlen(name); *dsId = malloc(nameLen + tmpLen + 2); if (!(*dsId)) { ret = DSLINK_ALLOC_ERR; goto exit; } memcpy(*dsId, name, nameLen); *(*dsId + nameLen) = '-'; memcpy((*dsId + nameLen + 1), (char *) tmp, tmpLen); *(*dsId + nameLen + tmpLen + 1) = '\0'; } { // Create the request body json_t *obj = json_object(); if (!obj) { ret = DSLINK_ALLOC_ERR; goto exit; } json_object_set_new(obj, "publicKey", json_string((char *) pubKey)); json_object_set_new(obj, "isRequester", json_boolean(isRequester)); json_object_set_new(obj, "isResponder", json_boolean(isResponder)); json_object_set_new(obj, "version", json_string("1.1.2")); body = json_dumps(obj, JSON_INDENT(2)); json_delete(obj); if (!body) { ret = DSLINK_ALLOC_ERR; goto exit; } } char req[512]; size_t reqLen; { char uri[128]; snprintf(uri, sizeof(uri), "%s?dsId=%s", url->uri, *dsId); reqLen = snprintf(req, sizeof(req), DSLINK_POST_REQ, uri, url->host, url->port, (int) strlen(body), body); } if ((ret = dslink_socket_connect(&sock, url->host, url->port, url->secure)) != 0) { goto exit; } dslink_socket_write(sock, req, reqLen); int respLen = 0; while (1) { char buf[1024]; int read = dslink_socket_read(sock, buf, sizeof(buf) - 1); if (read <= 0) { break; } if (resp == NULL) { resp = malloc((size_t) read + 1); if (!resp) { ret = DSLINK_ALLOC_ERR; goto exit; } respLen = read; memcpy(resp, buf, read); *(resp + respLen) = '\0'; } else { char *tmp = realloc(resp, (size_t) respLen + read + 1); if (!tmp) { free(resp); ret = DSLINK_ALLOC_ERR; goto exit; } resp = tmp; memcpy(resp + respLen, buf, read); respLen += read; *(resp + respLen) = '\0'; } } if (!resp) { ret = DSLINK_HANDSHAKE_NO_RESPONSE; goto exit; } char *index = strstr(resp, "401 Unauthorized"); if (index) { ret = DSLINK_HANDSHAKE_UNAUTHORIZED; goto exit; } index = strchr(resp, '{'); if (!index) { ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; goto exit; } char *json = index; index = strrchr(json, '}'); if (!index) { ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; goto exit; } *(index + 1) = '\0'; json_error_t jsonErr; *handshake = json_loads(json, 0, &jsonErr); if (!(*handshake)) { ret = DSLINK_ALLOC_ERR; goto exit; } const char *id = json_string_value(json_object_get(*handshake, "id")); if (id) { free(*dsId); size_t size = strlen(id) + 1; *dsId = malloc(size); if (!(*dsId)) { ret = DSLINK_ALLOC_ERR; json_delete(*handshake); *handshake = NULL; goto exit; } memcpy(*dsId, id, size); } exit: DSLINK_CHECKED_EXEC(free, body); DSLINK_CHECKED_EXEC(free, resp); DSLINK_CHECKED_EXEC(dslink_socket_close, sock); return ret; }