Ejemplo n.º 1
0
void kssl_write(SSL *ssl, kssl_header *k, kssl_operation *r)
{
    BYTE *req;
    int req_len, n;

    flatten_operation(k, r, &req, &req_len);

    dump_header(k, "send");
    dump_request(r);

    n = SSL_write(ssl, req, req_len);
    if (n != req_len) {
        fatal_error("Failed to send KSSL header");
    }
    free(req);
}
Ejemplo n.º 2
0
// kssl: send a KSSL message to the server and read the response
kssl_header *kssl(SSL *ssl, kssl_header *k, kssl_operation *r)
{
    BYTE buf[KSSL_HEADER_SIZE];
    BYTE *req;
    int req_len;
    int n;
    kssl_header h;
    kssl_header *to_return;

    flatten_operation(k, r, &req, &req_len);

    dump_header(k, "send");
    dump_request(r);

    n = SSL_write(ssl, req, req_len);
    if (n != req_len) {
        fatal_error("Failed to send KSSL header");
    }

    free(req);

    while (1) {
        n = SSL_read(ssl, buf, KSSL_HEADER_SIZE);
        if (n <= 0) {
            int x = SSL_get_error(ssl, n);
            if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) {
                continue;
            } else if (x == SSL_ERROR_ZERO_RETURN) {
                fatal_error("Connection closed while reading header\n");
            } else {
                fatal_error("Error performing SSL_read: %x\n", x);
            }
        } else {
            if (n != KSSL_HEADER_SIZE) {
                fatal_error("Error receiving KSSL header, size: %d", n);
            }
        }

        break;
    }

    parse_header(buf, &h);
    if (h.version_maj != KSSL_VERSION_MAJ) {
        fatal_error("Version mismatch %d != %d", h.version_maj, KSSL_VERSION_MAJ);
    }
    if (k->id != h.id) {
        fatal_error("ID mismatch %08x != %08x", k->id, h.id);
    }

    dump_header(&h, "recv");

    to_return = (kssl_header *)malloc(sizeof(kssl_header));
    memcpy(to_return, &h, sizeof(kssl_header));


    if (h.length > 0) {
        BYTE *payload = (BYTE *)malloc(h.length);
        while (1) {
            n = SSL_read(ssl, payload, h.length);
            if (n <= 0) {
                int x = SSL_get_error(ssl, n);
                if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) {
                    continue;
                } else if (x == SSL_ERROR_ZERO_RETURN) {
                    fatal_error("Connection closed while reading payload\n");
                } else {
                    fatal_error("Error performing SSL_read: %x\n", x);
                }
            } else {
                if (n != h.length) {
                    fatal_error("Error receiving KSSL payload, size: %d", n);
                }
            }

            break;
        }

        if (n != h.length) {
            fatal_error("Failed to read payload got length %d wanted %d", n, h.length);
        }

        dump_payload(h.length, payload);
        to_return->data = payload;
    }

    return to_return;
}
Ejemplo n.º 3
0
// 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;
}