void kssl_repeat_op_ping(connection *c, int repeat) { char hello[255]; kssl_header echo1; kssl_operation req, resp; kssl_header *h; int i; BYTE *payload = malloc(255 + 1); test("Repeat KSSL_OP_PING %d times (%p)", repeat, c); echo1.version_maj = KSSL_VERSION_MAJ; echo1.id = 0x12345679; zero_operation(&req); req.is_opcode_set = 1; req.is_payload_set = 1; req.opcode = KSSL_OP_PING; req.payload_len = 255 + 1; req.payload = payload; for (i = 0; i < repeat; i++) { sprintf(hello, "Hello, World! %d", i); memcpy((char *)payload, hello, strlen(hello)+1); req.payload_len = strlen(hello)+1; h = kssl(c->ssl, &echo1, &req); test_assert(h->id == echo1.id); test_assert(h->version_maj == KSSL_VERSION_MAJ); parse_message_payload(h->data, h->length, &resp); test_assert(resp.opcode == KSSL_OP_PONG); test_assert(resp.payload_len == req.payload_len); test_assert(strncmp((char *)resp.payload, (char *)req.payload, strlen(hello)) == 0); free(h->data); free(h); } ok(0); free(payload); }
void kssl_op_ping_payload(connection *c) { const char *hello = "Hello, World!"; kssl_operation req, resp; kssl_header echo1; kssl_header *h; BYTE *payload; test("KSSL_OP_PING with payload (%p)", c); payload = malloc(strlen(hello) + 1); echo1.version_maj = KSSL_VERSION_MAJ; echo1.id = 0x12345679; zero_operation(&req); req.is_opcode_set = 1; req.is_payload_set = 1; req.opcode = KSSL_OP_PING; req.payload_len = strlen(hello); req.payload = payload; memcpy((char *)payload, hello, strlen(hello)); h = kssl(c->ssl, &echo1, &req); test_assert(h->id == echo1.id); test_assert(h->version_maj == KSSL_VERSION_MAJ); parse_message_payload(h->data, h->length, &resp); test_assert(resp.opcode == KSSL_OP_PONG); test_assert(resp.payload_len == req.payload_len); test_assert(strncmp((char *)resp.payload, (char *)req.payload, strlen(hello)) == 0); ok(h); free(payload); }
void kssl_bad_opcode(connection *c) { kssl_header bad; kssl_operation req, resp; kssl_header *h; test("Bad KSSL opcode (%p)", c); bad.version_maj = KSSL_VERSION_MAJ; bad.version_min = KSSL_VERSION_MIN; bad.id = 0x12345678; bad.length = 0; // to be overridden by serialization zero_operation(&req); req.is_opcode_set = 1; req.is_payload_set = 1; req.opcode = 0xBB; req.payload_len = 0; h = kssl(c->ssl, &bad, &req); test_assert(h->id == bad.id); test_assert(h->version_maj == KSSL_VERSION_MAJ); parse_message_payload(h->data, h->length, &resp); test_assert(resp.opcode == KSSL_OP_ERROR); test_assert(resp.payload_len == 1); test_assert(resp.payload[0] == KSSL_ERROR_BAD_OPCODE); ok(h); }
void kssl_op_ping_bad_version(connection *c) { kssl_header echo0; kssl_operation req, resp; kssl_header *h; test("KSSL_OP_PING with bad version (%p)", c); echo0.id = 0x12345678; echo0.version_maj = KSSL_VERSION_MAJ+1; zero_operation(&req); req.is_opcode_set = 1; req.is_payload_set = 1; req.opcode = KSSL_OP_PING; req.payload_len = 0; h = kssl(c->ssl, &echo0, &req); test_assert(h->version_maj == KSSL_VERSION_MAJ); test_assert(h->id == echo0.id); parse_message_payload(h->data, h->length, &resp); test_assert(resp.opcode == KSSL_OP_ERROR); test_assert(resp.payload_len == 1); test_assert(resp.payload[0] == KSSL_ERROR_VERSION_MISMATCH); ok(h); }
void kssl_pipeline_op_ping(connection *c, int repeat) { char hello[255]; kssl_header echo1; kssl_operation req; BYTE *payload = malloc(255 + 1); test("Pipeline KSSL_OP_PING %d times (%p)", repeat, c); echo1.version_maj = KSSL_VERSION_MAJ; echo1.id = 0x12345679; zero_operation(&req); req.is_opcode_set = 1; req.is_payload_set = 1; req.opcode = KSSL_OP_PING; req.payload_len = 255 + 1; req.payload = payload; sprintf(hello, "Hello, World! Pipeline"); memcpy((char *)payload, hello, strlen(hello)+1); req.payload_len = strlen(hello)+1; kssl_pipeline(c->ssl, &echo1, &req, repeat); ok(0); free(payload); }
void kssl_op_error(connection *c) { kssl_header echo0; kssl_operation req, resp; kssl_header *h; test("KSSL_OP_ERROR (%p)", c); echo0.version_maj = KSSL_VERSION_MAJ; echo0.id = 0x12345678; zero_operation(&req); req.is_opcode_set = 1; req.is_payload_set = 1; req.opcode = KSSL_OP_ERROR; req.payload_len = 0; h = kssl(c->ssl, &echo0, &req); test_assert(h->id == echo0.id); test_assert(h->version_maj == KSSL_VERSION_MAJ); parse_message_payload(h->data, h->length, &resp); test_assert(resp.opcode == KSSL_OP_ERROR); test_assert(resp.payload_len == 1); test_assert(resp.payload[0] == KSSL_ERROR_UNEXPECTED_OPCODE); ok(h); }
// kssl_operate: create a serialized response from a KSSL request // header and payload kssl_error_code kssl_operate(kssl_header *header, BYTE *payload, pk_list privates, BYTE **out_response, int *out_response_len) { kssl_error_code err = KSSL_ERROR_NONE; BYTE *local_resp = NULL; int local_resp_len = 0; // Parse the indices of the items out of the payload kssl_header out_header; kssl_operation request; kssl_operation response; BYTE *out_payload = NULL; zero_operation(&request); zero_operation(&response); *out_response = 0; *out_response_len = 0; // Extract the items from the payload err = parse_message_payload(payload, header->length, &request); if (err != KSSL_ERROR_NONE) { goto exit; } if (silent == 0) { log_operation(header, &request); } switch (request.opcode) { // Other side sent response, error or pong: unexpected case KSSL_OP_RESPONSE: case KSSL_OP_ERROR: case KSSL_OP_PONG: { err = KSSL_ERROR_UNEXPECTED_OPCODE; break; } // Echo is trivial, it just echos the complete state->header back // including the payload item case KSSL_OP_PING: { response.is_payload_set = 1; response.payload = request.payload; response.payload_len = request.payload_len; response.is_opcode_set = 1; response.opcode = KSSL_OP_PONG; break; } // Decrypt or sign the payload using the private key case KSSL_OP_RSA_DECRYPT: case KSSL_OP_RSA_SIGN_MD5SHA1: case KSSL_OP_RSA_SIGN_SHA1: case KSSL_OP_RSA_SIGN_SHA224: case KSSL_OP_RSA_SIGN_SHA256: case KSSL_OP_RSA_SIGN_SHA384: case KSSL_OP_RSA_SIGN_SHA512: { unsigned int payload_size; int max_payload_size; int key_id; if (request.is_digest_set == 0) { err = KSSL_ERROR_FORMAT; break; } // Identify private key from request digest key_id = find_private_key(privates, request.digest); if (key_id < 0) { err = KSSL_ERROR_KEY_NOT_FOUND; break; } // Allocate buffer to hold output of private key operation max_payload_size = key_size(privates, key_id); out_payload = malloc(max_payload_size); if (out_payload == NULL) { err = KSSL_ERROR_INTERNAL; break; } // Operate on payload err = private_key_operation(privates, key_id, request.opcode, request.payload_len, request.payload, out_payload, &payload_size); if (err != KSSL_ERROR_NONE) { err = KSSL_ERROR_CRYPTO_FAILED; break; } response.is_payload_set = 1; response.payload = out_payload; response.payload_len = payload_size; response.is_opcode_set = 1; response.opcode = KSSL_OP_RESPONSE; break; } // This should not occur default: { err = KSSL_ERROR_BAD_OPCODE; break; } } exit: if (err != KSSL_ERROR_NONE) { err = kssl_error(header->id, err, &local_resp, &local_resp_len); } else { // Create output header out_header.version_maj = KSSL_VERSION_MAJ; out_header.version_min = KSSL_VERSION_MIN; out_header.id = header->id; // Note that the response in &local_resp is dynamically allocated // and needs to be freed err = flatten_operation(&out_header, &response, &local_resp, &local_resp_len); } if (out_payload != NULL) { free(out_payload); } if (err == KSSL_ERROR_NONE) { *out_response = local_resp; *out_response_len = local_resp_len; } return err; }
// parse_message_payload: parse a message payload into a // kssl_operation struct kssl_error_code parse_message_payload(BYTE *payload, // int len, // kssl_operation *operation) { // int offset = 0; kssl_item temp_item; if (payload == NULL || operation == NULL) { return KSSL_ERROR_INTERNAL; } zero_operation(operation); // Count number of items and validate structure while (offset < len) { if (len - offset < (int)(KSSL_ITEM_HEADER_SIZE)) { return KSSL_ERROR_FORMAT; } if (parse_item(payload, &offset, &temp_item) != KSSL_ERROR_NONE || len < offset) { return KSSL_ERROR_FORMAT; } // Iterate through known tags, populating necessary values switch (temp_item.tag) { case KSSL_TAG_OPCODE: { // Skip over malformed tags if (temp_item.length != 1) { continue; } operation->opcode = temp_item.data[0]; operation->is_opcode_set = 1; break; } case KSSL_TAG_DIGEST: { // Skip over malformed tags if (temp_item.length != KSSL_DIGEST_SIZE) continue; operation->digest = temp_item.data; operation->is_digest_set = 1; break; } case KSSL_TAG_PAYLOAD: { operation->payload_len = temp_item.length; operation->payload = temp_item.data; operation->is_payload_set = 1; break; } case KSSL_TAG_CLIENT_IP: { operation->ip_len = temp_item.length; operation->ip = temp_item.data; operation->is_ip_set = 1; break; } case KSSL_TAG_PADDING: { break; } default: break; } } // check to see if opcode and payload are set if (operation->is_opcode_set == 0 || operation->is_payload_set == 0) { return KSSL_ERROR_FORMAT; } return KSSL_ERROR_NONE; }