+ /* Check if the length of the meta key is all right */
+
+ if(inlen != len) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong keylength");
+ return false;
+ }
+
+ /* Decrypt the meta key */
+
+ if(!rsa_private_decrypt(myself->connection->rsa, enckey, len, key)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Error during decryption of meta key for %s (%s)", c->name, c->hostname);
+ return false;
+ }
+
+ if(debug_level >= DEBUG_SCARY_THINGS) {
+ bin2hex(key, hexkey, len);
+ logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Received random meta key (unencrypted): %s", hexkey);
+ }
+
+ /* Check and lookup cipher and digest algorithms */
+
+ if(cipher) {
+ if(!(c->incipher = cipher_open_by_nid(cipher)) || !cipher_set_key_from_rsa(c->incipher, key, len, false)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of cipher from %s (%s)", c->name, c->hostname);
+ return false;
+ }
+ } else {
+ c->incipher = NULL;
+ }
+
+ c->inbudget = cipher_budget(c->incipher);
+
+ if(digest) {
+ if(!(c->indigest = digest_open_by_nid(digest, -1))) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname);
+ return false;
+ }
+ } else {
+ c->indigest = NULL;
+ }
+
+ c->status.decryptin = true;
+
+ c->allow_request = CHALLENGE;
+
+ return send_challenge(c);
+#endif
+}
+
+bool send_challenge(connection_t *c) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
+ const size_t len = rsa_size(c->rsa);
+ char buffer[len * 2 + 1];
+
+ if(!c->hischallenge) {
+ c->hischallenge = xrealloc(c->hischallenge, len);
+ }
+
+ /* Copy random data to the buffer */
+
+ randomize(c->hischallenge, len);
+
+ /* Convert to hex */
+
+ bin2hex(c->hischallenge, buffer, len);
+
+ /* Send the challenge */
+
+ return send_request(c, "%d %s", CHALLENGE, buffer);
+#endif
+}
+
+bool challenge_h(connection_t *c, const char *request) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
+
+ if(!myself->connection->rsa) {
+ return false;
+ }
+
+ char buffer[MAX_STRING_SIZE];
+ const size_t len = rsa_size(myself->connection->rsa);
+ size_t digestlen = digest_length(c->indigest);
+ char digest[digestlen];
+
+ if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name, c->hostname);
+ return false;
+ }
+
+ /* Convert the challenge from hexadecimal back to binary */
+
+ int inlen = hex2bin(buffer, buffer, sizeof(buffer));
+
+ /* Check if the length of the challenge is all right */
+
+ if(inlen != len) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge length");
+ return false;
+ }
+
+ /* Calculate the hash from the challenge we received */
+
+ if(!digest_create(c->indigest, buffer, len, digest)) {
+ return false;
+ }
+
+ /* Convert the hash to a hexadecimal formatted string */
+
+ bin2hex(digest, buffer, digestlen);
+
+ /* Send the reply */
+
+ c->allow_request = CHAL_REPLY;
+
+ return send_request(c, "%d %s", CHAL_REPLY, buffer);
+#endif
+}
+
+bool chal_reply_h(connection_t *c, const char *request) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
+ char hishash[MAX_STRING_SIZE];
+
+ if(sscanf(request, "%*d " MAX_STRING, hishash) != 1) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "CHAL_REPLY", c->name,
+ c->hostname);
+ return false;
+ }
+
+ /* Convert the hash to binary format */
+
+ int inlen = hex2bin(hishash, hishash, sizeof(hishash));
+
+ /* Check if the length of the hash is all right */
+
+ if(inlen != digest_length(c->outdigest)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge reply length");
+ return false;
+ }
+
+
+ /* Verify the hash */
+
+ if(!digest_verify(c->outdigest, c->hischallenge, rsa_size(c->rsa), hishash)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge reply");
+ return false;
+ }
+
+ /* Identity has now been positively verified.
+ Send an acknowledgement with the rest of the information needed.
+ */
+
+ free(c->hischallenge);
+ c->hischallenge = NULL;
+ c->allow_request = ACK;
+
+ return send_ack(c);
+#endif