Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP4:Update
libssh2_org.11061
libssh2_org-knownhosts-handle-unknown-key-types...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libssh2_org-knownhosts-handle-unknown-key-types.patch of Package libssh2_org.11061
From 85c6627c861e970ba0bab10ec8b44b6523d6a5fd Mon Sep 17 00:00:00 2001 From: Salvador Fandino <sfandino@yahoo.com> Date: Sun, 27 Oct 2013 10:55:07 +0100 Subject: [PATCH] knownhosts: handle unknown key types Store but don't use keys of unsupported types on the known_hosts file. Currently, when libssh2 parses a known_host file containing keys of some type it doesn't natively support, it stops reading the file and returns an error. That means, that the known_host file can not be safely shared with other software supporting other key types (i.e. OpenSSH). This patch adds support for handling keys of unknown type. It can read and write them, even if they are never going to be matched. At the source level the patch does the following things: - add a new unknown key type LIBSSH2_KNOWNHOST_KEY_UNKNOWN - add a new slot (key_type_name) on the known_host struct that is used to store the key type in ascii form when it is not supported - parse correctly known_hosts entries with unknown key types and populate the key_type_name slot - print correctly known_hosts entries of unknown type - when checking a host key ignore keys that do not match the key Fixes #276 --- include/libssh2.h | 3 +- src/knownhost.c | 287 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 176 insertions(+), 114 deletions(-) diff --git a/include/libssh2.h b/include/libssh2.h index 1b0d690..172e9b3 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -865,11 +865,12 @@ libssh2_knownhost_init(LIBSSH2_SESSION *session); #define LIBSSH2_KNOWNHOST_KEYENC_BASE64 (2<<16) /* type of key (2 bits) */ -#define LIBSSH2_KNOWNHOST_KEY_MASK (3<<18) +#define LIBSSH2_KNOWNHOST_KEY_MASK (7<<18) #define LIBSSH2_KNOWNHOST_KEY_SHIFT 18 #define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18) #define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18) #define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18) +#define LIBSSH2_KNOWNHOST_KEY_UNKNOWN (7<<18) LIBSSH2_API int libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, diff --git a/src/knownhost.c b/src/knownhost.c index 8e1889c..fee6fb8 100644 --- a/src/knownhost.c +++ b/src/knownhost.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2011 by Daniel Stenberg + * Copyright (c) 2009-2013 by Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -50,7 +50,11 @@ struct known_host { size_t salt_len; /* size of salt */ char *key; /* the (allocated) associated key. This is kept base64 encoded in memory. */ - char *comment; /* the (allocated) optional comment text, may be NULL */ + char *key_type_name; /* the (allocated) key type name */ + size_t key_type_len; /* size of key_type_name */ + char *comment; /* the (allocated) optional comment text, may be + NULL */ + size_t comment_len; /* the size of comment */ /* this is the struct we expose externally */ struct libssh2_knownhost external; @@ -67,6 +71,8 @@ static void free_host(LIBSSH2_SESSION *session, struct known_host *entry) if(entry) { if(entry->comment) LIBSSH2_FREE(session, entry->comment); + if (entry->key_type_name) + LIBSSH2_FREE(session, entry->key_type_name); if(entry->key) LIBSSH2_FREE(session, entry->key); if(entry->salt) @@ -127,6 +133,7 @@ static struct libssh2_knownhost *knownhost_to_external(struct known_host *node) static int knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, const char *host, const char *salt, + const char *key_type_name, size_t key_type_len, const char *key, size_t keylen, const char *comment, size_t commentlen, int typemask, struct libssh2_knownhost **store) @@ -161,6 +168,7 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, goto error; } memcpy(entry->name, host, hostlen+1); + entry->name_len = hostlen; break; case LIBSSH2_KNOWNHOST_TYPE_SHA1: rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, @@ -210,6 +218,19 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, entry->key = ptr; } + if (key_type_name && ((typemask & LIBSSH2_KNOWNHOST_KEY_MASK) == + LIBSSH2_KNOWNHOST_KEY_UNKNOWN)) { + entry->key_type_name = LIBSSH2_ALLOC(hosts->session, key_type_len+1); + if (!entry->key_type_name) { + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for key type"); + goto error; + } + memcpy(entry->key_type_name, key_type_name, key_type_len); + entry->key_type_name[key_type_len]=0; + entry->key_type_len = key_type_len; + } + if (comment) { entry->comment = LIBSSH2_ALLOC(hosts->session, commentlen+1); if(!entry->comment) { @@ -219,6 +240,7 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, } memcpy(entry->comment, comment, commentlen+1); entry->comment[commentlen]=0; /* force a terminating zero trailer */ + entry->comment_len = commentlen; } else { entry->comment = NULL; @@ -264,8 +286,8 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, const char *key, size_t keylen, int typemask, struct libssh2_knownhost **store) { - return knownhost_add(hosts, host, salt, key, keylen, NULL, 0, typemask, - store); + return knownhost_add(hosts, host, salt, NULL, 0, key, keylen, NULL, + 0, typemask, store); } @@ -303,8 +325,8 @@ libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, const char *comment, size_t commentlen, int typemask, struct libssh2_knownhost **store) { - return knownhost_add(hosts, host, salt, key, keylen, comment, commentlen, - typemask, store); + return knownhost_add(hosts, host, salt, NULL, 0, key, keylen, + comment, commentlen, typemask, store); } /* @@ -414,23 +436,35 @@ knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, break; } if(match) { - /* host name 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 */ + 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); } @@ -573,6 +607,7 @@ libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts) */ static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts, const char *host, size_t hostlen, + const char *key_type_name, size_t key_type_len, const char *key, size_t keylen, int key_type, const char *comment, size_t commentlen) { @@ -607,7 +642,9 @@ static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts, memcpy(hostbuf, name, namelen); hostbuf[namelen]=0; - rc = knownhost_add(hosts, hostbuf, NULL, key, keylen, + rc = knownhost_add(hosts, hostbuf, NULL, + key_type_name, key_type_len, + key, keylen, comment, commentlen, key_type | LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL); @@ -627,6 +664,7 @@ static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts, /* |1|[salt]|[hash] */ static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts, const char *host, size_t hostlen, + const char *key_type_name, size_t key_type_len, const char *key, size_t keylen, int key_type, const char *comment, size_t commentlen) { @@ -670,9 +708,11 @@ static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts, memcpy(hostbuf, host, hostlen); hostbuf[hostlen]=0; - return knownhost_add(hosts, hostbuf, salt, key, keylen, comment, - commentlen, - key_type | LIBSSH2_KNOWNHOST_TYPE_SHA1 | + return knownhost_add(hosts, hostbuf, salt, + key_type_name, key_type_len, + key, keylen, + comment, commentlen, + key_type | LIBSSH2_KNOWNHOST_TYPE_SHA1 | LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL); } else @@ -694,7 +734,9 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, const char *key, size_t keylen) { const char *comment = NULL; + const char *key_type_name = NULL; size_t commentlen = 0; + size_t key_type_len; int key_type; /* make some checks that the lengths seem sensible */ @@ -703,7 +745,7 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, "Failed to parse known_hosts line " "(key too short)"); - + switch(key[0]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': @@ -716,19 +758,21 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, */ break; - case 's': /* ssh-dss or ssh-rsa */ - if(!strncmp(key, "ssh-dss", 7)) + default: + key_type_name = key; + while (keylen && *key && + (*key != ' ') && (*key != '\t')) { + key++; + keylen--; + } + key_type_len = key - key_type_name; + + if (!strncmp(key_type_name, "ssh-dss", key_type_len)) key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS; - else if(!strncmp(key, "ssh-rsa", 7)) + if (!strncmp(key_type_name, "ssh-rsa", key_type_len)) key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA; else - /* unknown key type */ - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unknown key type"); - - key += 7; - keylen -= 7; + key_type = LIBSSH2_KNOWNHOST_KEY_UNKNOWN; /* skip whitespaces */ while((*key ==' ') || (*key == '\t')) { @@ -760,11 +804,6 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, commentlen--; } break; - - default: /* unknown key format */ - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unknown key format"); } /* Figure out host format */ @@ -774,12 +813,14 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, for the sake of simplicity, we add them as separate hosts with the same key */ - return oldstyle_hostline(hosts, host, hostlen, key, keylen, key_type, + return oldstyle_hostline(hosts, host, hostlen, key_type_name, + key_type_len, key, keylen, key_type, comment, commentlen); } else { /* |1|[salt]|[hash] */ - return hashed_hostline(hosts, host, hostlen, key, keylen, key_type, + return hashed_hostline(hosts, host, hostlen, key_type_name, + key_type_len, key, keylen, key_type, comment, commentlen); } } @@ -943,17 +984,9 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, char *buf, size_t buflen, size_t *outlen, int type) { - int rc = LIBSSH2_ERROR_NONE; - int tindex; - const char *keytypes[4]={ - "", /* not used */ - "", /* this type has no name in the file */ - " ssh-rsa", - " ssh-dss" - }; - const char *keytype; - size_t nlen; - size_t commentlen = 0; + const char *key_type_name; + size_t key_type_len; + size_t offset = 0; /* we only support this single file type for now, bail out on all other attempts */ @@ -963,75 +996,103 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, "Unsupported type of known-host information " "store"); - tindex = (node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) >> - LIBSSH2_KNOWNHOST_KEY_SHIFT; - - /* set the string used in the file */ - keytype = keytypes[tindex]; - - /* calculate extra space needed for comment */ - if(node->comment) - commentlen = strlen(node->comment) + 1; + switch(node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { + case LIBSSH2_KNOWNHOST_KEY_RSA1: + key_type_name = NULL; + key_type_len = 0; + break; + case LIBSSH2_KNOWNHOST_KEY_SSHRSA: + key_type_name = "ssh-rsa"; + key_type_len = 7; + break; + case LIBSSH2_KNOWNHOST_KEY_SSHDSS: + key_type_name = "ssh-dss"; + key_type_len = 7; + break; + case LIBSSH2_KNOWNHOST_KEY_UNKNOWN: + key_type_name = node->key_type_name; + if (key_type_name) { + key_type_len = node->key_type_len; + break; + } + /* otherwise fallback to default and error */ + default: + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unsupported type of known-host entry"); + } if((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == LIBSSH2_KNOWNHOST_TYPE_SHA1) { - char *namealloc; - char *saltalloc; - nlen = _libssh2_base64_encode(hosts->session, node->name, - node->name_len, &namealloc); - if(!nlen) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "base64-encoded host name"); - - nlen = _libssh2_base64_encode(hosts->session, - node->salt, node->salt_len, - &saltalloc); - if(!nlen) { + int rc = LIBSSH2_ERROR_NONE; + char *namealloc = NULL; + char *saltalloc = NULL; + if (_libssh2_base64_encode(hosts->session, node->name, + node->name_len, &namealloc) && + _libssh2_base64_encode(hosts->session, + node->salt, node->salt_len, + &saltalloc)) + offset = snprintf(buf, buflen, "|1|%s|%s", saltalloc, namealloc); + else + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable allocate memory for known-host line"); + + if (namealloc) free(namealloc); - return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "base64-encoded salt"); - } + if (saltalloc) + LIBSSH2_FREE(hosts->session, saltalloc); - nlen = strlen(saltalloc) + strlen(namealloc) + strlen(keytype) + - strlen(node->key) + commentlen + 7; - /* |1| + | + ' ' + \n + \0 = 7 */ - - if(nlen <= buflen) - if(node->comment) - snprintf(buf, buflen, "|1|%s|%s%s %s %s\n", saltalloc, namealloc, - keytype, node->key, node->comment); - else - snprintf(buf, buflen, "|1|%s|%s%s %s\n", saltalloc, namealloc, - keytype, node->key); - else - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Known-host write buffer too small"); + if (rc != LIBSSH2_ERROR_NONE) + return rc; - free(namealloc); - free(saltalloc); + if (buflen <= offset) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Known-host write buffer too small"); } else { - nlen = strlen(node->name) + strlen(keytype) + strlen(node->key) + - commentlen + 3; - /* ' ' + '\n' + \0 = 3 */ - if(nlen <= buflen) - /* these types have the plain name */ - if(node->comment) - snprintf(buf, buflen, "%s%s %s %s\n", node->name, keytype, node->key, - node->comment); - else - snprintf(buf, buflen, "%s%s %s\n", node->name, keytype, node->key); - else - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Known-host write buffer too small"); + if (buflen <= node->name_len) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Known-host write buffer too small"); + memcpy(buf, node->name, node->name_len); + offset = node->name_len; } - /* we report the full length of the data with the trailing zero excluded */ - *outlen = nlen-1; + if (key_type_name) { + buf[offset++] = ' '; + if (buflen - offset <= key_type_len) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Known-host write buffer too small"); + memcpy(buf + offset, key_type_name, key_type_len); + offset += key_type_len; + } - return rc; + offset += snprintf(buf + offset, buflen - offset, + " %s", node->key); + if (buflen <= offset) + return _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Known-host write buffer too small"); + + if (node->comment) { + buf[offset++] = ' '; + if (buflen - offset <= node->comment_len) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Known-host write buffer too small"); + memcpy(buf + offset, node->comment, node->comment_len); + offset += node->comment_len; + } + + if (buflen - offset <= 1) + return _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Known-host write buffer too small"); + buf[offset++] = '\n'; + + buf[offset] = '\0'; + *outlen = offset; + return LIBSSH2_ERROR_NONE; } /* -- 2.12.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor