Exemple #1
0
static void
choose_enc(Enc *enc, char *client, char *server)
{
	char *name = match_list(client, server, NULL);
	if (name == NULL)
		fatal("no matching cipher found: client %s server %s", client, server);
	if ((enc->cipher = cipher_by_name(name)) == NULL)
		fatal("matching cipher is not supported: %s", name);
	enc->name = name;
	enc->enabled = 0;
	enc->iv = NULL;
	enc->key = NULL;
	enc->key_len = cipher_keylen(enc->cipher);
	enc->block_size = cipher_blocksize(enc->cipher);
}
Exemple #2
0
static int
choose_enc(Enc *enc, char *client, char *server)
{
	char *name = match_list(client, server, NULL);

	if (name == NULL)
		return SSH_ERR_NO_CIPHER_ALG_MATCH;
	if ((enc->cipher = cipher_by_name(name)) == NULL)
		return SSH_ERR_INTERNAL_ERROR;
	enc->name = name;
	enc->enabled = 0;
	enc->iv = NULL;
	enc->key = NULL;
	enc->key_len = cipher_keylen(enc->cipher);
	enc->block_size = cipher_blocksize(enc->cipher);
	return 0;
}
Exemple #3
0
int
sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b,
   struct sshbuf **retp)
{
	struct ssh_xmss_state *state = k->xmss_state;
	struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL;
	struct sshcipher_ctx *ciphercontext = NULL;
	const struct sshcipher *cipher;
	u_char *cp, *key, *iv = NULL;
	size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen;
	int r = SSH_ERR_INTERNAL_ERROR;

	if (retp != NULL)
		*retp = NULL;
	if (state == NULL ||
	    state->enc_keyiv == NULL ||
	    state->enc_ciphername == NULL)
		return SSH_ERR_INTERNAL_ERROR;
	if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) {
		r = SSH_ERR_INTERNAL_ERROR;
		goto out;
	}
	blocksize = cipher_blocksize(cipher);
	keylen = cipher_keylen(cipher);
	ivlen = cipher_ivlen(cipher);
	authlen = cipher_authlen(cipher);
	if (state->enc_keyiv_len != keylen + ivlen) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	key = state->enc_keyiv;
	if ((encrypted = sshbuf_new()) == NULL ||
	    (encoded = sshbuf_new()) == NULL ||
	    (padded = sshbuf_new()) == NULL ||
	    (iv = malloc(ivlen)) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}

	/* replace first 4 bytes of IV with index to ensure uniqueness */
	memcpy(iv, key + keylen, ivlen);
	POKE_U32(iv, state->idx);

	if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 ||
	    (r = sshbuf_put_u32(encoded, state->idx)) != 0)
		goto out;

	/* padded state will be encrypted */
	if ((r = sshbuf_putb(padded, b)) != 0)
		goto out;
	i = 0;
	while (sshbuf_len(padded) % blocksize) {
		if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0)
			goto out;
	}
	encrypted_len = sshbuf_len(padded);

	/* header including the length of state is used as AAD */
	if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0)
		goto out;
	aadlen = sshbuf_len(encoded);

	/* concat header and state */
	if ((r = sshbuf_putb(encoded, padded)) != 0)
		goto out;

	/* reserve space for encryption of encoded data plus auth tag */
	/* encrypt at offset addlen */
	if ((r = sshbuf_reserve(encrypted,
	    encrypted_len + aadlen + authlen, &cp)) != 0 ||
	    (r = cipher_init(&ciphercontext, cipher, key, keylen,
	    iv, ivlen, 1)) != 0 ||
	    (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded),
	    encrypted_len, aadlen, authlen)) != 0)
		goto out;

	/* success */
	r = 0;
 out:
	if (retp != NULL) {
		*retp = encrypted;
		encrypted = NULL;
	}
	sshbuf_free(padded);
	sshbuf_free(encoded);
	sshbuf_free(encrypted);
	cipher_free(ciphercontext);
	free(iv);
	return r;
}
Exemple #4
0
int
sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded,
   struct sshbuf **retp)
{
	struct ssh_xmss_state *state = k->xmss_state;
	struct sshbuf *copy = NULL, *decrypted = NULL;
	struct sshcipher_ctx *ciphercontext = NULL;
	const struct sshcipher *cipher = NULL;
	u_char *key, *iv = NULL, *dp;
	size_t keylen, ivlen, authlen, aadlen;
	u_int blocksize, encrypted_len, index;
	int r = SSH_ERR_INTERNAL_ERROR;

	if (retp != NULL)
		*retp = NULL;
	if (state == NULL ||
	    state->enc_keyiv == NULL ||
	    state->enc_ciphername == NULL)
		return SSH_ERR_INTERNAL_ERROR;
	if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	blocksize = cipher_blocksize(cipher);
	keylen = cipher_keylen(cipher);
	ivlen = cipher_ivlen(cipher);
	authlen = cipher_authlen(cipher);
	if (state->enc_keyiv_len != keylen + ivlen) {
		r = SSH_ERR_INTERNAL_ERROR;
		goto out;
	}
	key = state->enc_keyiv;

	if ((copy = sshbuf_fromb(encoded)) == NULL ||
	    (decrypted = sshbuf_new()) == NULL ||
	    (iv = malloc(ivlen)) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}

	/* check magic */
	if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) ||
	    memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	/* parse public portion */
	if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 ||
	    (r = sshbuf_get_u32(encoded, &index)) != 0 ||
	    (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0)
		goto out;

	/* check size of encrypted key blob */
	if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	/* check that an appropriate amount of auth data is present */
	if (sshbuf_len(encoded) < encrypted_len + authlen) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}

	aadlen = sshbuf_len(copy) - sshbuf_len(encoded);

	/* replace first 4 bytes of IV with index to ensure uniqueness */
	memcpy(iv, key + keylen, ivlen);
	POKE_U32(iv, index);

	/* decrypt private state of key */
	if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 ||
	    (r = cipher_init(&ciphercontext, cipher, key, keylen,
	    iv, ivlen, 0)) != 0 ||
	    (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy),
	    encrypted_len, aadlen, authlen)) != 0)
		goto out;

	/* there should be no trailing data */
	if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0)
		goto out;
	if (sshbuf_len(encoded) != 0) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}

	/* remove AAD */
	if ((r = sshbuf_consume(decrypted, aadlen)) != 0)
		goto out;
	/* XXX encrypted includes unchecked padding */

	/* success */
	r = 0;
	if (retp != NULL) {
		*retp = decrypted;
		decrypted = NULL;
	}
 out:
	cipher_free(ciphercontext);
	sshbuf_free(copy);
	sshbuf_free(decrypted);
	free(iv);
	return r;
}
Exemple #5
0
int ENTRY_NAME(int argc, const char* argv[]) {
    const char **p = alloca(argc * sizeof(char*));
    struct master_config config;
    char* keybuf;

    memcpy(p, argv + 1, (argc - 1) * sizeof(char*));
    p[argc - 1] = 0;

    if (--argc == 0) {
        fprintf(stderr, "Usage:\n");
        fprintf(stderr, "\tmultex --dev <name> --interface <name> \n");
        return 2;
    }

    config.interfaces.next = &config.interfaces;
    config.sessions.next = &config.sessions;
    config.endpoints.next = &config.endpoints;
    config.rendpoints.next = &config.rendpoints;
    config.port = 1389;
    config.event_base = event_base_new();
    config.tracker = tracker_create(config.event_base, &config, (tracker_callback_t)tracker_callback);
    if (config.tracker == 0) {
        return 1;
    }

    config.cipher = cipher_bf();
    config.cipher_keysize = cipher_keysize(config.cipher);
    config.cipher_size = cipher_blocksize(config.cipher);
    keybuf = alloca(config.cipher_keysize);

    config.trackerhost = "tracker.publicbt.com:80";
    memset(keybuf, 0, config.cipher_keysize);
    config.key0 = cipher_context_create(config.cipher, keybuf);
    random_bytes(keybuf, config.cipher_keysize);
    config.keyX = cipher_context_create(config.cipher, keybuf);

    config.digest = digest_context_create(digest_sha());
    config.digest_size = digest_size(digest_sha());

    while (*p != 0) {
        const char* cmd = *p++;
        if (strcmp(cmd, "--tracker") == 0) {
            if (*p == 0) {
                fprintf(stderr, "tracker address expected\n");
                return 2;
            }
            tracker_add(config.tracker, *p++);
            continue;
        }
        if (strcmp(cmd, "--remote") == 0) {
            struct udpaddress address;
            if (*p == 0) {
                fprintf(stderr, "remote address expected\n");
                return 2;
            }
            udpaddress_resolve(&address, *p++);
            tracker_callback(&config, &address, 0);
            continue;
        }
        if (strcmp(cmd, "--dev") == 0) {
            if (*p == 0) {
                fprintf(stderr, "Device name expected\n");

                return 2;
            }
            fprintf(stderr, "Creating device %s...\n", *p);
            config.master_fd = tun_create(*p++);
            if (config.master_fd < 0) {
                return 1;
            }
            config.master_event = event_new(config.event_base, config.master_fd, EV_READ | EV_PERSIST, (event_callback_fn)master_callback, &config);
            event_add(config.master_event, 0);
            continue;
        }
        if (strcmp(cmd, "--interface") == 0 || strcmp(cmd, "-i") == 0) {

            const char *name = *p++;
            struct interface *interface = malloc(sizeof(struct interface));

            if (name == 0) {
                fprintf(stderr, "interface name expected\n");
                return 2;
            }

            interface->priority = 1;
            interface->weight = 1;
            interface->name = strdup(name);
            interface->next = config.interfaces.next;
            interface->active = 0;
            config.interfaces.next = interface;
            continue;
        }
        fprintf(stderr, "Unknown option: %s\n", cmd);
        return 2;
    }

    /*open interfaces*/
    config.inotify = inotify_create(config.event_base, &config, (inotification_callback_t)inotify_callback);
    if (config.inotify == 0) {
        return 1;
    }


    {
        struct if_nameindex *ifp = if_nameindex();
        struct if_nameindex *p = ifp;
        struct ifaddrs *ifaddr;
        struct ifaddrs *ifa;

        if (getifaddrs(&ifaddr) == -1) {
            perror("getifaddrs");
            return 1;
        }

        while (p->if_index > 0 && p->if_name != 0) {
            struct inotification notification;

            notification.device = p->if_name;
            notification.type = INOTIFY_INT_ADDED;
            inotify_callback(&config, &notification);

            for (ifa = ifaddr; ifa != 0; ifa = ifa->ifa_next) {
               notification.address.family = ifa->ifa_addr->sa_family;
               if (strcmp(ifa->ifa_name, p->if_name) != 0) {
                   continue;
               }
               notification.type = INOTIFY_ADDR_ADDED;
               /* For an AF_INET* interface address, display the address */
               if (notification.address.family == AF_INET) {
                    notification.address.addr4 =  ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
               } else
               if (notification.address.family == AF_INET6) {
                    notification.address.addr6 =  ((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr;
               } else {
                    continue;
               }
               inotify_callback(&config, &notification);
           }

            p++;
        }
        if_freenameindex(ifp);

        freeifaddrs(ifaddr);

    }

    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
    config.stdin_event = event_new(config.event_base, STDIN_FILENO, EV_READ | EV_PERSIST, (event_callback_fn)stdin_callback, &config);
    event_add(config.stdin_event, 0);

    {
        struct timeval timeval;
        timeval.tv_sec = 10;
        timeval.tv_usec = 0;
        config.reconnect_event = event_new(config.event_base, -1, EV_PERSIST, (event_callback_fn)reconnect_callback, &config);
        evtimer_add(config.reconnect_event, &timeval);
    }

    reconnect_callback(-1, EV_TIMEOUT, &config);
    event_base_dispatch(config.event_base);


    return 0;
}