Example #1
0
int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password,
                  ptrlen *new_password_opt)
{
    const char *PHONY_GOOD_PASSWORD = "******";
    const char *PHONY_BAD_PASSWORD = "******";

    if (!new_password_opt) {
        /* Accept login with our preconfigured good password */
        if (ptrlen_eq_string(password, PHONY_GOOD_PASSWORD))
            return 1;
        /* Don't outright reject the bad password, but insist on a change */
        if (ptrlen_eq_string(password, PHONY_BAD_PASSWORD))
            return 2;
        /* Reject anything else */
        return 0;
    } else {
        /* In a password-change request, expect the bad password as input */
        if (!ptrlen_eq_string(password, PHONY_BAD_PASSWORD))
            return 0;
        /* Accept a request to change it to the good password */
        if (ptrlen_eq_string(*new_password_opt, PHONY_GOOD_PASSWORD))
            return 1;
        /* Outright reject a request to change it to the same password
         * as it already 'was' */
        if (ptrlen_eq_string(*new_password_opt, PHONY_BAD_PASSWORD))
            return 0;
        /* Anything else, pretend the new pw wasn't good enough, and
         * re-request a change */
        return 2;
    }
}
Example #2
0
static ssh_key *ecdsa_new_pub(const ssh_keyalg *alg, ptrlen data)
{
    const struct ecsign_extra *extra =
        (const struct ecsign_extra *)alg->extra;
    struct ec_curve *curve = extra->curve();
    assert(curve->type == EC_WEIERSTRASS);

    BinarySource src[1];
    BinarySource_BARE_INIT_PL(src, data);
    get_string(src);

    /* Curve name is duplicated for Weierstrass form */
    if (!ptrlen_eq_string(get_string(src), curve->name))
        return NULL;

    struct ecdsa_key *ek = snew(struct ecdsa_key);
    ek->sshk.vt = alg;
    ek->curve = curve;
    ek->privateKey = NULL;

    ek->publicKey = get_wpoint(src, curve);
    if (!ek->publicKey) {
        ecdsa_freekey(&ek->sshk);
        return NULL;
    }

    return &ek->sshk;
}
Example #3
0
ChanopenResult ssh2_connection_parse_channel_open(
    struct ssh2_connection_state *s, ptrlen type,
    PktIn *pktin, SshChannel *sc)
{
    if (ptrlen_eq_string(type, "session")) {
        return chan_open_session(s, sc);
    } else if (ptrlen_eq_string(type, "direct-tcpip")) {
        ptrlen dstaddr = get_string(pktin);
        int dstport = toint(get_uint32(pktin));
        ptrlen peeraddr = get_string(pktin);
        int peerport = toint(get_uint32(pktin));
        return chan_open_direct_tcpip(
            s, sc, dstaddr, dstport, peeraddr, peerport);
    } else {
        CHANOPEN_RETURN_FAILURE(
            SSH2_OPEN_UNKNOWN_CHANNEL_TYPE,
            ("Unsupported channel type requested"));
    }
}
Example #4
0
int auth_kbdint_responses(AuthPolicy *ap, const ptrlen *responses)
{
    switch (ap->kbdint_state) {
      case 0:
        if (ptrlen_eq_string(responses[0], "stoat") &&
            ptrlen_eq_string(responses[1], "weasel")) {
            ap->kbdint_state++;
            return 0;                  /* those are the expected responses */
        } else {
            ap->kbdint_state = 0;
            return -1;
        }
        break;
      case 1:
        return +1;                     /* succeed after the zero-prompt step */
      default:
        ap->kbdint_state = 0;
        return -1;
    }
}
Example #5
0
bool ssh2_connection_parse_global_request(
    struct ssh2_connection_state *s, ptrlen type, PktIn *pktin)
{
    if (ptrlen_eq_string(type, "tcpip-forward")) {
        char *host = mkstr(get_string(pktin));
        unsigned port = get_uint32(pktin);
        /* In SSH-2, the host/port we listen on are the same host/port
         * we want reported back to us when a connection comes in,
         * because that's what we tell the client */
        bool toret = portfwdmgr_listen(
            s->portfwdmgr, host, port, host, port, s->conf);
        sfree(host);
        return toret;
    } else if (ptrlen_eq_string(type, "cancel-tcpip-forward")) {
        char *host = mkstr(get_string(pktin));
        unsigned port = get_uint32(pktin);
        bool toret = portfwdmgr_unlisten(s->portfwdmgr, host, port);
        sfree(host);
        return toret;
    } else {
        /* Unrecognised request. */
        return false;
    }
}
Example #6
0
static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
{
    RSAKey *rsa = container_of(key, RSAKey, sshk);
    BinarySource src[1];
    ptrlen type, in_pl;
    mp_int *in, *out;

    /* If we need to support variable flags on verify, this is where they go */
    const ssh_hashalg *halg = rsa2_hash_alg_for_flags(0, NULL);

    /* Start by making sure the key is even long enough to encode a
     * signature. If not, everything fails to verify. */
    size_t nbytes = (mp_get_nbits(rsa->modulus) + 7) / 8;
    if (nbytes < rsa_pkcs1_length_of_fixed_parts(halg))
        return false;

    BinarySource_BARE_INIT_PL(src, sig);
    type = get_string(src);
    /*
     * RFC 4253 section 6.6: the signature integer in an ssh-rsa
     * signature is 'without lengths or padding'. That is, we _don't_
     * expect the usual leading zero byte if the topmost bit of the
     * first byte is set. (However, because of the possibility of
     * BUG_SSH2_RSA_PADDING at the other end, we tolerate it if it's
     * there.) So we can't use get_mp_ssh2, which enforces that
     * leading-byte scheme; instead we use get_string and
     * mp_from_bytes_be, which will tolerate anything.
     */
    in_pl = get_string(src);
    if (get_err(src) || !ptrlen_eq_string(type, "ssh-rsa"))
	return false;

    in = mp_from_bytes_be(in_pl);
    out = mp_modpow(in, rsa->exponent, rsa->modulus);
    mp_free(in);

    unsigned diff = 0;

    unsigned char *bytes = rsa_pkcs1_signature_string(nbytes, halg, data);
    for (size_t i = 0; i < nbytes; i++)
        diff |= bytes[nbytes-1 - i] ^ mp_get_byte(out, i);
    smemclr(bytes, nbytes);
    sfree(bytes);
    mp_free(out);

    return diff == 0;
}
Example #7
0
static bool eddsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
{
    struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk);
    const struct ecsign_extra *extra =
        (const struct ecsign_extra *)ek->sshk.vt->extra;

    BinarySource src[1];
    BinarySource_BARE_INIT_PL(src, sig);

    /* Check the signature starts with the algorithm name */
    if (!ptrlen_eq_string(get_string(src), ek->sshk.vt->ssh_id))
        return false;

    /* Now expect a single string which is the concatenation of an
     * encoded curve point r and an integer s. */
    ptrlen sigstr = get_string(src);
    if (get_err(src))
        return false;
    BinarySource_BARE_INIT_PL(src, sigstr);
    ptrlen rstr = get_data(src, ek->curve->fieldBytes);
    ptrlen sstr = get_data(src, ek->curve->fieldBytes);
    if (get_err(src) || get_avail(src))
        return false;

    EdwardsPoint *r = eddsa_decode(rstr, ek->curve);
    if (!r)
        return false;
    mp_int *s = mp_from_bytes_le(sstr);

    mp_int *H = eddsa_signing_exponent_from_data(ek, extra, rstr, data);

    /* Verify that s*G == r + H*publicKey */
    EdwardsPoint *lhs = ecc_edwards_multiply(ek->curve->e.G, s);
    mp_free(s);
    EdwardsPoint *hpk = ecc_edwards_multiply(ek->publicKey, H);
    mp_free(H);
    EdwardsPoint *rhs = ecc_edwards_add(r, hpk);
    ecc_edwards_point_free(hpk);
    unsigned valid = ecc_edwards_eq(lhs, rhs);
    ecc_edwards_point_free(lhs);
    ecc_edwards_point_free(rhs);
    ecc_edwards_point_free(r);

    return valid;
}
Example #8
0
static ssh_key *rsa2_new_pub(const ssh_keyalg *self, ptrlen data)
{
    BinarySource src[1];
    RSAKey *rsa;

    BinarySource_BARE_INIT_PL(src, data);
    if (!ptrlen_eq_string(get_string(src), "ssh-rsa"))
	return NULL;

    rsa = snew(RSAKey);
    rsa->sshk.vt = &ssh_rsa;
    rsa->exponent = get_mp_ssh2(src);
    rsa->modulus = get_mp_ssh2(src);
    rsa->private_exponent = NULL;
    rsa->p = rsa->q = rsa->iqmp = NULL;
    rsa->comment = NULL;

    if (get_err(src)) {
	rsa2_freekey(&rsa->sshk);
	return NULL;
    }

    return &rsa->sshk;
}
Example #9
0
int ssh2_censor_packet(
    const PacketLogSettings *pls, int type, int sender_is_client,
    ptrlen pkt, logblank_t *blanks)
{
    int nblanks = 0;
    ptrlen str;
    BinarySource src[1];

    BinarySource_BARE_INIT(src, pkt.ptr, pkt.len);

    if (pls->omit_data &&
        (type == SSH2_MSG_CHANNEL_DATA ||
         type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) {
        /* "Session data" packets - omit the data string. */
        get_uint32(src);              /* skip channel id */
        if (type == SSH2_MSG_CHANNEL_EXTENDED_DATA)
            get_uint32(src);          /* skip extended data type */
        str = get_string(src);
        if (!get_err(src)) {
            assert(nblanks < MAX_BLANKS);
            blanks[nblanks].offset = src->pos - str.len;
            blanks[nblanks].type = PKTLOG_OMIT;
            blanks[nblanks].len = str.len;
            nblanks++;
        }
    }

    if (sender_is_client && pls->omit_passwords) {
        if (type == SSH2_MSG_USERAUTH_REQUEST) {
            /* If this is a password packet, blank the password(s). */
            get_string(src);              /* username */
            get_string(src);              /* service name */
            str = get_string(src);        /* auth method */
            if (ptrlen_eq_string(str, "password")) {
                get_bool(src);
                /* Blank the password field. */
                str = get_string(src);
                if (!get_err(src)) {
                    assert(nblanks < MAX_BLANKS);
                    blanks[nblanks].offset = src->pos - str.len;
                    blanks[nblanks].type = PKTLOG_BLANK;
                    blanks[nblanks].len = str.len;
                    nblanks++;
                    /* If there's another password field beyond it
                     * (change of password), blank that too. */
                    str = get_string(src);
                    if (!get_err(src))
                        blanks[nblanks-1].len =
                            src->pos - blanks[nblanks].offset;
                }
            }
        } else if (pls->actx == SSH2_PKTCTX_KBDINTER &&
                   type == SSH2_MSG_USERAUTH_INFO_RESPONSE) {
            /* If this is a keyboard-interactive response packet,
             * blank the responses. */
            get_uint32(src);
            assert(nblanks < MAX_BLANKS);
            blanks[nblanks].offset = src->pos;
            blanks[nblanks].type = PKTLOG_BLANK;
            do {
                str = get_string(src);
            } while (!get_err(src));
            blanks[nblanks].len = src->pos - blanks[nblanks].offset;
            nblanks++;
        } else if (type == SSH2_MSG_CHANNEL_REQUEST) {
            /*
             * If this is an X forwarding request packet, blank the
             * fake auth data.
             *
             * Note that while we blank the X authentication data
             * here, we don't take any special action to blank the
             * start of an X11 channel, so using MIT-MAGIC-COOKIE-1
             * and actually opening an X connection without having
             * session blanking enabled is likely to leak your cookie
             * into the log.
             */
            get_uint32(src);
            str = get_string(src);
            if (ptrlen_eq_string(str, "x11-req")) {
                get_bool(src);
                get_bool(src);
                get_string(src);
                str = get_string(src);
                if (!get_err(src)) {
                    assert(nblanks < MAX_BLANKS);
                    blanks[nblanks].offset = src->pos - str.len;
                    blanks[nblanks].type = PKTLOG_BLANK;
                    blanks[nblanks].len = str.len;
                    nblanks++;
                }
            }
        }
    }

    return nblanks;
}
Example #10
0
static bool ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
{
    struct ecdsa_key *ek = container_of(key, struct ecdsa_key, sshk);
    const struct ecsign_extra *extra =
        (const struct ecsign_extra *)ek->sshk.vt->extra;

    BinarySource src[1];
    BinarySource_BARE_INIT_PL(src, sig);

    /* Check the signature starts with the algorithm name */
    if (!ptrlen_eq_string(get_string(src), ek->sshk.vt->ssh_id))
        return false;

    /* Everything else is nested inside a sub-string. Descend into that. */
    ptrlen sigstr = get_string(src);
    if (get_err(src))
        return false;
    BinarySource_BARE_INIT_PL(src, sigstr);

    /* Extract the signature integers r,s */
    mp_int *r = get_mp_ssh2(src);
    mp_int *s = get_mp_ssh2(src);
    if (get_err(src)) {
        mp_free(r);
        mp_free(s);
        return false;
    }

    /* Basic sanity checks: 0 < r,s < order(G) */
    unsigned invalid = 0;
    invalid |= mp_eq_integer(r, 0);
    invalid |= mp_eq_integer(s, 0);
    invalid |= mp_cmp_hs(r, ek->curve->w.G_order);
    invalid |= mp_cmp_hs(s, ek->curve->w.G_order);

    /* Get the hash of the signed data, converted to an integer */
    mp_int *z = ecdsa_signing_exponent_from_data(ek->curve, extra, data);

    /* Verify the signature integers against the hash */
    mp_int *w = mp_invert(s, ek->curve->w.G_order);
    mp_int *u1 = mp_modmul(z, w, ek->curve->w.G_order);
    mp_free(z);
    mp_int *u2 = mp_modmul(r, w, ek->curve->w.G_order);
    mp_free(w);
    WeierstrassPoint *u1G = ecc_weierstrass_multiply(ek->curve->w.G, u1);
    mp_free(u1);
    WeierstrassPoint *u2P = ecc_weierstrass_multiply(ek->publicKey, u2);
    mp_free(u2);
    WeierstrassPoint *sum = ecc_weierstrass_add_general(u1G, u2P);
    ecc_weierstrass_point_free(u1G);
    ecc_weierstrass_point_free(u2P);

    mp_int *x;
    ecc_weierstrass_get_affine(sum, &x, NULL);
    ecc_weierstrass_point_free(sum);

    mp_divmod_into(x, ek->curve->w.G_order, NULL, x);
    invalid |= (1 ^ mp_cmp_eq(r, x));
    mp_free(x);

    mp_free(r);
    mp_free(s);

    return !invalid;
}
Example #11
0
bool auth_ssh1int_response(AuthPolicy *ap, ptrlen response)
{
    return ptrlen_eq_string(response, "otter");
}