Example #1
0
File: mac.c Project: Zenju/libssh2
/* mac_method_hmac_sha256_hash
 * Calculate hash using full sha256 value
 */
static int
mac_method_hmac_sha2_256_hash(LIBSSH2_SESSION * session,
                          unsigned char *buf, uint32_t seqno,
                          const unsigned char *packet,
                          uint32_t packet_len,
                          const unsigned char *addtl,
                          uint32_t addtl_len, void **abstract)
{
    libssh2_hmac_ctx ctx;
    unsigned char seqno_buf[4];
    (void) session;

    _libssh2_htonu32(seqno_buf, seqno);

    libssh2_hmac_ctx_init(ctx);
    libssh2_hmac_sha256_init(&ctx, *abstract, 32);
    libssh2_hmac_update(ctx, seqno_buf, 4);
    libssh2_hmac_update(ctx, packet, packet_len);
    if(addtl && addtl_len) {
        libssh2_hmac_update(ctx, addtl, addtl_len);
    }
    libssh2_hmac_final(ctx, buf);
    libssh2_hmac_cleanup(&ctx);

    return 0;
}
Example #2
0
/*
 * libssh2_knownhost_check
 *
 * Check a host and its associated key against the collection of known hosts.
 *
 * The typemask is the type/format of the given host name and key
 *
 * plain  - ascii "hostname.domain.tld"
 * sha1   - NOT SUPPORTED AS INPUT
 * custom - prehashed base64 encoded. Note that this cannot use any salts.
 *
 * Returns:
 *
 * LIBSSH2_KNOWNHOST_CHECK_FAILURE
 * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND
 * LIBSSH2_KNOWNHOST_CHECK_MATCH
 * LIBSSH2_KNOWNHOST_CHECK_MISMATCH
 */
LIBSSH2_API int
libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
                        const char *host, const char *key, size_t keylen,
                        int typemask,
                        struct libssh2_knownhost **ext)
{
    struct known_host *node = _libssh2_list_first(&hosts->head);
    struct known_host *badkey = NULL;
    int type = typemask & LIBSSH2_KNOWNHOST_TYPE_MASK;
    char *keyalloc = NULL;
    int rc = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND;

    if(type == LIBSSH2_KNOWNHOST_TYPE_SHA1)
        /* we can't work with a sha1 as given input */
        return LIBSSH2_KNOWNHOST_CHECK_MISMATCH;

    if(!(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64)) {
        /* we got a raw key input, convert it to base64 for the checks below */
        size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen,
                                             &keyalloc);
        if(!nlen)
            return LIBSSH2_KNOWNHOST_CHECK_FAILURE;

        /* make the key point to this */
        key = keyalloc;
        keylen = nlen;
    }

    while (node) {
        int match = 0;
        switch(node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) {
        case LIBSSH2_KNOWNHOST_TYPE_PLAIN:
            if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN)
                match = !strcmp(host, node->name);
            break;
        case LIBSSH2_KNOWNHOST_TYPE_CUSTOM:
            if(type == LIBSSH2_KNOWNHOST_TYPE_CUSTOM)
                match = !strcmp(host, node->name);
            break;
        case LIBSSH2_KNOWNHOST_TYPE_SHA1:
            if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) {
                /* when we have the sha1 version stored, we can use a plain
                   input to produce a hash to compare with the stored hash.
                */
                libssh2_hmac_ctx ctx;
                unsigned char hash[SHA_DIGEST_LENGTH];

                if(SHA_DIGEST_LENGTH != node->name_len) {
                    /* the name hash length must be the sha1 size or
                       we can't match it */
                    break;
                }
                libssh2_hmac_sha1_init(&ctx, node->salt, node->salt_len);
                libssh2_hmac_update(ctx, (unsigned char *)host, strlen(host));
                libssh2_hmac_final(ctx, hash);
                libssh2_hmac_cleanup(&ctx);

                if(!memcmp(hash, node->name, SHA_DIGEST_LENGTH))
                    /* this is a node we're interested in */
                    match = 1;
            }
            break;
        default: /* unsupported type */
            break;
        }
        if(match) {
            /* host name match, now compare the keys */
            if(!strcmp(key, node->key)) {
                /* they match! */
                *ext = knownhost_to_external(node);
                badkey = NULL;
                rc = LIBSSH2_KNOWNHOST_CHECK_MATCH;
                break;
            }
            else {
                /* remember the first node that had a host match but a failed
                   key match since we continue our search from here */
                if(!badkey)
                    badkey = node;
            }
        }
        node= _libssh2_list_next(&node->node);
    }

    if(badkey) {
        /* key mismatch */
        *ext = knownhost_to_external(badkey);
        rc = LIBSSH2_KNOWNHOST_CHECK_MISMATCH;
    }

    if(keyalloc)
        LIBSSH2_FREE(hosts->session, keyalloc);

    return rc;
}
Example #3
0
/*
 * knownhost_check
 *
 * Check a host and its associated key against the collection of known hosts.
 *
 * The typemask is the type/format of the given host name and key
 *
 * plain  - ascii "hostname.domain.tld"
 * sha1   - NOT SUPPORTED AS INPUT
 * custom - prehashed base64 encoded. Note that this cannot use any salts.
 *
 * Returns:
 *
 * LIBSSH2_KNOWNHOST_CHECK_FAILURE
 * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND
 * LIBSSH2_KNOWNHOST_CHECK_MATCH
 * LIBSSH2_KNOWNHOST_CHECK_MISMATCH
 */
static int
knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
                const char *hostp, int port,
                const char *key, size_t keylen,
                int typemask,
                struct libssh2_knownhost **ext)
{
    struct known_host *node;
    struct known_host *badkey = NULL;
    int type = typemask & LIBSSH2_KNOWNHOST_TYPE_MASK;
    char *keyalloc = NULL;
    int rc = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND;
    char hostbuff[270]; /* most host names can't be longer than like 256 */
    const char *host;
    int numcheck; /* number of host combos to check */
    int match = 0;

    if(type == LIBSSH2_KNOWNHOST_TYPE_SHA1)
        /* we can't work with a sha1 as given input */
        return LIBSSH2_KNOWNHOST_CHECK_MISMATCH;

    /* if a port number is given, check for a '[host]:port' first before the
       plain 'host' */
    if(port >= 0) {
        int len = snprintf(hostbuff, sizeof(hostbuff), "[%s]:%d", hostp, port);
        if (len < 0 || len >= (int)sizeof(hostbuff)) {
            _libssh2_error(hosts->session,
                           LIBSSH2_ERROR_BUFFER_TOO_SMALL,
                           "Known-host write buffer too small");
            return LIBSSH2_KNOWNHOST_CHECK_FAILURE;
        }
        host = hostbuff;
        numcheck = 2; /* check both combos, start with this */
    }
    else {
        host = hostp;
        numcheck = 1; /* only check this host version */
    }

    if(!(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64)) {
        /* we got a raw key input, convert it to base64 for the checks below */
        size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen,
                                             &keyalloc);
        if(!nlen) {
            _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
                           "Unable to allocate memory for base64-encoded "
                           "key");
            return LIBSSH2_KNOWNHOST_CHECK_FAILURE;
        }

        /* make the key point to this */
        key = keyalloc;
    }

    do {
        node = _libssh2_list_first(&hosts->head);
        while (node) {
            switch(node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) {
            case LIBSSH2_KNOWNHOST_TYPE_PLAIN:
                if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN)
                    match = !strcmp(host, node->name);
                break;
            case LIBSSH2_KNOWNHOST_TYPE_CUSTOM:
                if(type == LIBSSH2_KNOWNHOST_TYPE_CUSTOM)
                    match = !strcmp(host, node->name);
                break;
            case LIBSSH2_KNOWNHOST_TYPE_SHA1:
                if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) {
                    /* when we have the sha1 version stored, we can use a
                       plain input to produce a hash to compare with the
                       stored hash.
                    */
                    libssh2_hmac_ctx ctx;
                    unsigned char hash[SHA_DIGEST_LENGTH];

                    if(SHA_DIGEST_LENGTH != node->name_len) {
                        /* the name hash length must be the sha1 size or
                           we can't match it */
                        break;
                    }
                    libssh2_hmac_sha1_init(&ctx, (unsigned char *)node->salt,
                                           node->salt_len);
                    libssh2_hmac_update(ctx, (unsigned char *)host,
                                        strlen(host));
                    libssh2_hmac_final(ctx, hash);
                    libssh2_hmac_cleanup(&ctx);

                    if(!memcmp(hash, node->name, SHA_DIGEST_LENGTH))
                        /* this is a node we're interested in */
                        match = 1;
                }
                break;
            default: /* unsupported type */
                break;
            }
            if(match) {
                int host_key_type = typemask & LIBSSH2_KNOWNHOST_KEY_MASK;
                int known_key_type =
                    node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK;
                /* match on key type as follows:
                   - never match on an unknown key type
                   - if key_type is set to zero, ignore it an match always
                   - otherwise match when both key types are equal
                */
                if ( (host_key_type != LIBSSH2_KNOWNHOST_KEY_UNKNOWN ) &&
                     ( (host_key_type == 0) ||
                       (host_key_type == known_key_type) ) ) {
                    /* host name and key type match, now compare the keys */
                    if(!strcmp(key, node->key)) {
                        /* they match! */
                        if (ext)
                            *ext = knownhost_to_external(node);
                        badkey = NULL;
                        rc = LIBSSH2_KNOWNHOST_CHECK_MATCH;
                        break;
                    }
                    else {
                        /* remember the first node that had a host match but a
                           failed key match since we continue our search from
                           here */
                        if(!badkey)
                            badkey = node;
                    }
                }
                match = 0; /* don't count this as a match anymore */
            }
            node= _libssh2_list_next(&node->node);
        }
        host = hostp;
    } while(!match && --numcheck);

    if(badkey) {
        /* key mismatch */
        if (ext)
            *ext = knownhost_to_external(badkey);
        rc = LIBSSH2_KNOWNHOST_CHECK_MISMATCH;
    }

    if(keyalloc)
        LIBSSH2_FREE(hosts->session, keyalloc);

    return rc;
}