1
0
mirror of http://galexander.org/git/simplesshd.git synced 2024-11-27 17:58:13 +00:00
simplesshd/dropbear/signkey.c

781 lines
20 KiB
C
Raw Normal View History

2014-12-10 21:56:49 +00:00
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "signkey.h"
#include "buffer.h"
#include "ssh.h"
#include "ecdsa.h"
2020-12-28 21:40:37 +00:00
#include "rsa.h"
#include "dss.h"
#include "ed25519.h"
2014-12-10 21:56:49 +00:00
2019-06-09 20:44:26 +00:00
static const char * const signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
#if DROPBEAR_RSA
2014-12-10 21:56:49 +00:00
"ssh-rsa",
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2014-12-10 21:56:49 +00:00
"ssh-dss",
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
2014-12-10 21:56:49 +00:00
"ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384",
2020-12-28 21:40:37 +00:00
"ecdsa-sha2-nistp521",
2014-12-10 21:56:49 +00:00
#endif /* DROPBEAR_ECDSA */
2020-12-28 21:40:37 +00:00
#if DROPBEAR_ED25519
"ssh-ed25519",
#endif /* DROPBEAR_ED25519 */
/* "rsa-sha2-256" is special-cased below since it is only a signature name, not key type */
2014-12-10 21:56:49 +00:00
};
/* malloc a new sign_key and set the dss and rsa keys to NULL */
sign_key * new_sign_key() {
sign_key * ret;
ret = (sign_key*)m_malloc(sizeof(sign_key));
ret->type = DROPBEAR_SIGNKEY_NONE;
ret->source = SIGNKEY_SOURCE_INVALID;
return ret;
}
/* Returns key name corresponding to the type. Exits fatally
* if the type is invalid */
const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen) {
if (type >= DROPBEAR_SIGNKEY_NUM_NAMED) {
dropbear_exit("Bad key type %d", type);
}
if (namelen) {
*namelen = strlen(signkey_names[type]);
}
return signkey_names[type];
}
/* Returns DROPBEAR_SIGNKEY_NONE if none match */
enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) {
int i;
for (i = 0; i < DROPBEAR_SIGNKEY_NUM_NAMED; i++) {
const char *fixed_name = signkey_names[i];
if (namelen == strlen(fixed_name)
&& memcmp(fixed_name, name, namelen) == 0) {
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
2014-12-10 21:56:49 +00:00
/* Some of the ECDSA key sizes are defined even if they're not compiled in */
if (0
2019-06-09 20:44:26 +00:00
#if !DROPBEAR_ECC_256
2014-12-10 21:56:49 +00:00
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP256
#endif
2019-06-09 20:44:26 +00:00
#if !DROPBEAR_ECC_384
2014-12-10 21:56:49 +00:00
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP384
#endif
2019-06-09 20:44:26 +00:00
#if !DROPBEAR_ECC_521
2014-12-10 21:56:49 +00:00
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP521
#endif
) {
TRACE(("attempt to use ecdsa type %d not compiled in", i))
return DROPBEAR_SIGNKEY_NONE;
}
#endif
2019-06-09 20:44:26 +00:00
return (enum signkey_type)i;
2014-12-10 21:56:49 +00:00
}
}
TRACE(("signkey_type_from_name unexpected key type."))
return DROPBEAR_SIGNKEY_NONE;
}
2020-12-28 21:40:37 +00:00
/* Special case for rsa-sha2-256. This could be generalised if more
signature names are added that aren't 1-1 with public key names */
const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) {
#if DROPBEAR_RSA_SHA256
if (type == DROPBEAR_SIGNATURE_RSA_SHA256) {
if (namelen) {
*namelen = strlen(SSH_SIGNATURE_RSA_SHA256);
}
return SSH_SIGNATURE_RSA_SHA256;
}
#endif
#if DROPBEAR_RSA_SHA1
if (type == DROPBEAR_SIGNATURE_RSA_SHA1) {
if (namelen) {
*namelen = strlen(SSH_SIGNKEY_RSA);
}
return SSH_SIGNKEY_RSA;
}
#endif
return signkey_name_from_type((enum signkey_type)type, namelen);
}
/* Returns DROPBEAR_SIGNATURE_NONE if none match */
enum signature_type signature_type_from_name(const char* name, unsigned int namelen) {
#if DROPBEAR_RSA_SHA256
if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256)
&& memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) {
return DROPBEAR_SIGNATURE_RSA_SHA256;
}
#endif
#if DROPBEAR_RSA_SHA1
if (namelen == strlen(SSH_SIGNKEY_RSA)
&& memcmp(name, SSH_SIGNKEY_RSA, namelen) == 0) {
return DROPBEAR_SIGNATURE_RSA_SHA1;
}
#endif
return (enum signature_type)signkey_type_from_name(name, namelen);
}
/* Returns the signature type from a key type. Must not be called
with RSA keytype */
enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
#if DROPBEAR_RSA
assert(keytype != DROPBEAR_SIGNKEY_RSA);
#endif
assert(keytype < DROPBEAR_SIGNKEY_NUM_NAMED);
return (enum signature_type)keytype;
}
enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
#if DROPBEAR_RSA_SHA256
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
return DROPBEAR_SIGNKEY_RSA;
}
#endif
#if DROPBEAR_RSA_SHA1
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA1) {
return DROPBEAR_SIGNKEY_RSA;
}
#endif
assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED);
return (enum signkey_type)sigtype;
}
2019-06-09 20:44:26 +00:00
/* Returns a pointer to the key part specific to "type".
Be sure to check both (ret != NULL) and (*ret != NULL) */
2014-12-10 21:56:49 +00:00
void **
signkey_key_ptr(sign_key *key, enum signkey_type type) {
switch (type) {
2020-12-28 21:40:37 +00:00
#if DROPBEAR_ED25519
case DROPBEAR_SIGNKEY_ED25519:
return (void**)&key->ed25519key;
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
#if DROPBEAR_ECC_256
2014-12-10 21:56:49 +00:00
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return (void**)&key->ecckey256;
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECC_384
2014-12-10 21:56:49 +00:00
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
return (void**)&key->ecckey384;
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECC_521
2014-12-10 21:56:49 +00:00
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
return (void**)&key->ecckey521;
#endif
#endif /* DROPBEAR_ECDSA */
2019-06-09 20:44:26 +00:00
#if DROPBEAR_RSA
2014-12-10 21:56:49 +00:00
case DROPBEAR_SIGNKEY_RSA:
return (void**)&key->rsakey;
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2014-12-10 21:56:49 +00:00
case DROPBEAR_SIGNKEY_DSS:
return (void**)&key->dsskey;
#endif
default:
return NULL;
}
}
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
* type should be set by the caller to specify the type to read, and
* on return is set to the type read (useful when type = _ANY) */
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
2019-06-09 20:44:26 +00:00
char *ident;
2014-12-10 21:56:49 +00:00
unsigned int len;
2019-06-09 20:44:26 +00:00
enum signkey_type keytype;
2014-12-10 21:56:49 +00:00
int ret = DROPBEAR_FAILURE;
TRACE2(("enter buf_get_pub_key"))
ident = buf_getstring(buf, &len);
keytype = signkey_type_from_name(ident, len);
m_free(ident);
if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype, *type))
return DROPBEAR_FAILURE;
}
TRACE2(("buf_get_pub_key keytype is %d", keytype))
*type = keytype;
/* Rewind the buffer back before "ssh-rsa" etc */
2020-12-28 21:40:37 +00:00
buf_decrpos(buf, len + 4);
2014-12-10 21:56:49 +00:00
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2014-12-10 21:56:49 +00:00
if (keytype == DROPBEAR_SIGNKEY_DSS) {
dss_key_free(key->dsskey);
key->dsskey = m_malloc(sizeof(*key->dsskey));
ret = buf_get_dss_pub_key(buf, key->dsskey);
if (ret == DROPBEAR_FAILURE) {
2019-06-09 20:44:26 +00:00
dss_key_free(key->dsskey);
key->dsskey = NULL;
2014-12-10 21:56:49 +00:00
}
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_RSA
2014-12-10 21:56:49 +00:00
if (keytype == DROPBEAR_SIGNKEY_RSA) {
rsa_key_free(key->rsakey);
key->rsakey = m_malloc(sizeof(*key->rsakey));
ret = buf_get_rsa_pub_key(buf, key->rsakey);
if (ret == DROPBEAR_FAILURE) {
2019-06-09 20:44:26 +00:00
rsa_key_free(key->rsakey);
key->rsakey = NULL;
2014-12-10 21:56:49 +00:00
}
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
2014-12-10 21:56:49 +00:00
if (signkey_is_ecdsa(keytype)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck) {
if (*eck) {
ecc_free(*eck);
2019-06-09 20:44:26 +00:00
m_free(*eck);
2014-12-10 21:56:49 +00:00
*eck = NULL;
}
*eck = buf_get_ecdsa_pub_key(buf);
if (*eck) {
ret = DROPBEAR_SUCCESS;
}
}
}
#endif
2020-12-28 21:40:37 +00:00
#if DROPBEAR_ED25519
if (keytype == DROPBEAR_SIGNKEY_ED25519) {
ed25519_key_free(key->ed25519key);
key->ed25519key = m_malloc(sizeof(*key->ed25519key));
ret = buf_get_ed25519_pub_key(buf, key->ed25519key);
if (ret == DROPBEAR_FAILURE) {
m_free(key->ed25519key);
key->ed25519key = NULL;
}
}
#endif
2014-12-10 21:56:49 +00:00
TRACE2(("leave buf_get_pub_key"))
return ret;
}
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
* type should be set by the caller to specify the type to read, and
* on return is set to the type read (useful when type = _ANY) */
int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
2019-06-09 20:44:26 +00:00
char *ident;
2014-12-10 21:56:49 +00:00
unsigned int len;
2019-06-09 20:44:26 +00:00
enum signkey_type keytype;
2014-12-10 21:56:49 +00:00
int ret = DROPBEAR_FAILURE;
TRACE2(("enter buf_get_priv_key"))
ident = buf_getstring(buf, &len);
keytype = signkey_type_from_name(ident, len);
m_free(ident);
if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
TRACE(("wrong key type: %d %d", *type, keytype))
return DROPBEAR_FAILURE;
}
*type = keytype;
/* Rewind the buffer back before "ssh-rsa" etc */
2020-12-28 21:40:37 +00:00
buf_decrpos(buf, len + 4);
2014-12-10 21:56:49 +00:00
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2014-12-10 21:56:49 +00:00
if (keytype == DROPBEAR_SIGNKEY_DSS) {
dss_key_free(key->dsskey);
key->dsskey = m_malloc(sizeof(*key->dsskey));
ret = buf_get_dss_priv_key(buf, key->dsskey);
if (ret == DROPBEAR_FAILURE) {
2019-06-09 20:44:26 +00:00
dss_key_free(key->dsskey);
key->dsskey = NULL;
2014-12-10 21:56:49 +00:00
}
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_RSA
2014-12-10 21:56:49 +00:00
if (keytype == DROPBEAR_SIGNKEY_RSA) {
rsa_key_free(key->rsakey);
key->rsakey = m_malloc(sizeof(*key->rsakey));
ret = buf_get_rsa_priv_key(buf, key->rsakey);
if (ret == DROPBEAR_FAILURE) {
2019-06-09 20:44:26 +00:00
rsa_key_free(key->rsakey);
key->rsakey = NULL;
2014-12-10 21:56:49 +00:00
}
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
2014-12-10 21:56:49 +00:00
if (signkey_is_ecdsa(keytype)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck) {
if (*eck) {
ecc_free(*eck);
2019-06-09 20:44:26 +00:00
m_free(*eck);
2014-12-10 21:56:49 +00:00
*eck = NULL;
}
*eck = buf_get_ecdsa_priv_key(buf);
if (*eck) {
ret = DROPBEAR_SUCCESS;
}
}
}
#endif
2020-12-28 21:40:37 +00:00
#if DROPBEAR_ED25519
if (keytype == DROPBEAR_SIGNKEY_ED25519) {
ed25519_key_free(key->ed25519key);
key->ed25519key = m_malloc(sizeof(*key->ed25519key));
ret = buf_get_ed25519_priv_key(buf, key->ed25519key);
if (ret == DROPBEAR_FAILURE) {
m_free(key->ed25519key);
key->ed25519key = NULL;
}
}
#endif
2014-12-10 21:56:49 +00:00
TRACE2(("leave buf_get_priv_key"))
return ret;
}
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
buffer *pubkeys;
TRACE2(("enter buf_put_pub_key"))
pubkeys = buf_new(MAX_PUBKEY_SIZE);
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2014-12-10 21:56:49 +00:00
if (type == DROPBEAR_SIGNKEY_DSS) {
buf_put_dss_pub_key(pubkeys, key->dsskey);
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_RSA
2014-12-10 21:56:49 +00:00
if (type == DROPBEAR_SIGNKEY_RSA) {
buf_put_rsa_pub_key(pubkeys, key->rsakey);
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
2014-12-10 21:56:49 +00:00
if (signkey_is_ecdsa(type)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
2019-06-09 20:44:26 +00:00
if (eck && *eck) {
2014-12-10 21:56:49 +00:00
buf_put_ecdsa_pub_key(pubkeys, *eck);
}
}
2020-12-28 21:40:37 +00:00
#endif
#if DROPBEAR_ED25519
if (type == DROPBEAR_SIGNKEY_ED25519) {
buf_put_ed25519_pub_key(pubkeys, key->ed25519key);
}
2014-12-10 21:56:49 +00:00
#endif
if (pubkeys->len == 0) {
dropbear_exit("Bad key types in buf_put_pub_key");
}
buf_putbufstring(buf, pubkeys);
buf_free(pubkeys);
TRACE2(("leave buf_put_pub_key"))
}
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) {
TRACE(("enter buf_put_priv_key"))
TRACE(("type is %d", type))
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2014-12-10 21:56:49 +00:00
if (type == DROPBEAR_SIGNKEY_DSS) {
buf_put_dss_priv_key(buf, key->dsskey);
2019-06-09 20:44:26 +00:00
TRACE(("leave buf_put_priv_key: dss done"))
return;
2014-12-10 21:56:49 +00:00
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_RSA
2014-12-10 21:56:49 +00:00
if (type == DROPBEAR_SIGNKEY_RSA) {
buf_put_rsa_priv_key(buf, key->rsakey);
2019-06-09 20:44:26 +00:00
TRACE(("leave buf_put_priv_key: rsa done"))
return;
2014-12-10 21:56:49 +00:00
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
2014-12-10 21:56:49 +00:00
if (signkey_is_ecdsa(type)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
2019-06-09 20:44:26 +00:00
if (eck && *eck) {
2014-12-10 21:56:49 +00:00
buf_put_ecdsa_priv_key(buf, *eck);
TRACE(("leave buf_put_priv_key: ecdsa done"))
return;
}
}
2020-12-28 21:40:37 +00:00
#endif
#if DROPBEAR_ED25519
if (type == DROPBEAR_SIGNKEY_ED25519) {
buf_put_ed25519_priv_key(buf, key->ed25519key);
TRACE(("leave buf_put_priv_key: ed25519 done"))
return;
}
2014-12-10 21:56:49 +00:00
#endif
dropbear_exit("Bad key types in put pub key");
}
void sign_key_free(sign_key *key) {
TRACE2(("enter sign_key_free"))
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2014-12-10 21:56:49 +00:00
dss_key_free(key->dsskey);
key->dsskey = NULL;
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_RSA
2014-12-10 21:56:49 +00:00
rsa_key_free(key->rsakey);
key->rsakey = NULL;
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
#if DROPBEAR_ECC_256
2014-12-10 21:56:49 +00:00
if (key->ecckey256) {
ecc_free(key->ecckey256);
2019-06-09 20:44:26 +00:00
m_free(key->ecckey256);
2014-12-10 21:56:49 +00:00
key->ecckey256 = NULL;
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECC_384
2014-12-10 21:56:49 +00:00
if (key->ecckey384) {
ecc_free(key->ecckey384);
2019-06-09 20:44:26 +00:00
m_free(key->ecckey384);
2014-12-10 21:56:49 +00:00
key->ecckey384 = NULL;
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECC_521
2014-12-10 21:56:49 +00:00
if (key->ecckey521) {
ecc_free(key->ecckey521);
2019-06-09 20:44:26 +00:00
m_free(key->ecckey521);
2014-12-10 21:56:49 +00:00
key->ecckey521 = NULL;
}
#endif
2020-12-28 21:40:37 +00:00
#endif
#if DROPBEAR_ED25519
ed25519_key_free(key->ed25519key);
key->ed25519key = NULL;
2014-12-10 21:56:49 +00:00
#endif
m_free(key->filename);
m_free(key);
TRACE2(("leave sign_key_free"))
}
static char hexdig(unsigned char x) {
if (x > 0xf)
return 'X';
if (x < 10)
return '0' + x;
else
return 'a' + x - 10;
}
/* Since we're not sure if we'll have md5 or sha1, we present both.
* MD5 is used in preference, but sha1 could still be useful */
2019-06-09 20:44:26 +00:00
#if DROPBEAR_MD5_HMAC
static char * sign_key_md5_fingerprint(const unsigned char* keyblob,
2014-12-10 21:56:49 +00:00
unsigned int keybloblen) {
char * ret;
hash_state hs;
unsigned char hash[MD5_HASH_SIZE];
unsigned int i;
unsigned int buflen;
md5_init(&hs);
/* skip the size int of the string - this is a bit messy */
md5_process(&hs, keyblob, keybloblen);
md5_done(&hs, hash);
/* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
buflen = 4 + 3*MD5_HASH_SIZE;
ret = (char*)m_malloc(buflen);
memset(ret, 'Z', buflen);
strcpy(ret, "md5 ");
for (i = 0; i < MD5_HASH_SIZE; i++) {
unsigned int pos = 4 + i*3;
ret[pos] = hexdig(hash[i] >> 4);
ret[pos+1] = hexdig(hash[i] & 0x0f);
ret[pos+2] = ':';
}
ret[buflen-1] = 0x0;
return ret;
}
#else /* use SHA1 rather than MD5 for fingerprint */
2019-06-09 20:44:26 +00:00
static char * sign_key_sha1_fingerprint(const unsigned char* keyblob,
2014-12-10 21:56:49 +00:00
unsigned int keybloblen) {
char * ret;
hash_state hs;
unsigned char hash[SHA1_HASH_SIZE];
unsigned int i;
unsigned int buflen;
sha1_init(&hs);
/* skip the size int of the string - this is a bit messy */
sha1_process(&hs, keyblob, keybloblen);
sha1_done(&hs, hash);
/* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
buflen = 7 + 3*SHA1_HASH_SIZE;
ret = (char*)m_malloc(buflen);
strcpy(ret, "sha1!! ");
for (i = 0; i < SHA1_HASH_SIZE; i++) {
unsigned int pos = 7 + 3*i;
ret[pos] = hexdig(hash[i] >> 4);
ret[pos+1] = hexdig(hash[i] & 0x0f);
ret[pos+2] = ':';
}
ret[buflen-1] = 0x0;
return ret;
}
#endif /* MD5/SHA1 switch */
/* This will return a freshly malloced string, containing a fingerprint
* in either sha1 or md5 */
2019-06-09 20:44:26 +00:00
char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen) {
2014-12-10 21:56:49 +00:00
2019-06-09 20:44:26 +00:00
#if DROPBEAR_MD5_HMAC
2014-12-10 21:56:49 +00:00
return sign_key_md5_fingerprint(keyblob, keybloblen);
#else
return sign_key_sha1_fingerprint(keyblob, keybloblen);
#endif
}
2020-12-28 21:40:37 +00:00
void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
2019-06-09 20:44:26 +00:00
const buffer *data_buf) {
2020-12-28 21:40:37 +00:00
buffer *sigblob = buf_new(MAX_PUBKEY_SIZE);
enum signkey_type keytype = signkey_type_from_signature(sigtype);
#if DEBUG_TRACE
{
const char* signame = signature_name_from_type(sigtype, NULL);
TRACE(("buf_put_sign type %d %s", sigtype, signame));
}
#endif
2014-12-10 21:56:49 +00:00
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2020-12-28 21:40:37 +00:00
if (keytype == DROPBEAR_SIGNKEY_DSS) {
2014-12-10 21:56:49 +00:00
buf_put_dss_sign(sigblob, key->dsskey, data_buf);
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_RSA
2020-12-28 21:40:37 +00:00
if (keytype == DROPBEAR_SIGNKEY_RSA) {
buf_put_rsa_sign(sigblob, key->rsakey, sigtype, data_buf);
2014-12-10 21:56:49 +00:00
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
2020-12-28 21:40:37 +00:00
if (signkey_is_ecdsa(keytype)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
2019-06-09 20:44:26 +00:00
if (eck && *eck) {
2014-12-10 21:56:49 +00:00
buf_put_ecdsa_sign(sigblob, *eck, data_buf);
}
}
2020-12-28 21:40:37 +00:00
#endif
#if DROPBEAR_ED25519
if (keytype == DROPBEAR_SIGNKEY_ED25519) {
buf_put_ed25519_sign(sigblob, key->ed25519key, data_buf);
}
2014-12-10 21:56:49 +00:00
#endif
if (sigblob->len == 0) {
dropbear_exit("Non-matching signing type");
}
buf_putbufstring(buf, sigblob);
buf_free(sigblob);
}
2019-06-09 20:44:26 +00:00
#if DROPBEAR_SIGNKEY_VERIFY
2014-12-10 21:56:49 +00:00
/* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
* If FAILURE is returned, the position of
* buf is undefined. If SUCCESS is returned, buf will be positioned after the
* signature blob */
2020-12-28 21:40:37 +00:00
int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf) {
2014-12-10 21:56:49 +00:00
2019-06-09 20:44:26 +00:00
char *type_name = NULL;
2014-12-10 21:56:49 +00:00
unsigned int type_name_len = 0;
2020-12-28 21:40:37 +00:00
enum signature_type sigtype;
enum signkey_type keytype;
2014-12-10 21:56:49 +00:00
TRACE(("enter buf_verify"))
buf_getint(buf); /* blob length */
type_name = buf_getstring(buf, &type_name_len);
2020-12-28 21:40:37 +00:00
sigtype = signature_type_from_name(type_name, type_name_len);
2014-12-10 21:56:49 +00:00
m_free(type_name);
2021-01-18 00:32:53 +00:00
if (((expect_sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) &&
(sigtype == DROPBEAR_SIGNATURE_RSA_SHA1)) ||
((expect_sigtype == DROPBEAR_SIGNATURE_RSA_SHA1) &&
(sigtype == DROPBEAR_SIGNATURE_RSA_SHA256))) {
/* ignore mismatch between different flavors of ssh-rsa
* - Greg 2021/01/17 */
} else if (expect_sigtype != sigtype) {
2020-12-28 21:40:37 +00:00
dropbear_exit("Non-matching signing type");
}
keytype = signkey_type_from_signature(sigtype);
2019-06-09 20:44:26 +00:00
#if DROPBEAR_DSS
2020-12-28 21:40:37 +00:00
if (keytype == DROPBEAR_SIGNKEY_DSS) {
2014-12-10 21:56:49 +00:00
if (key->dsskey == NULL) {
dropbear_exit("No DSS key to verify signature");
}
return buf_dss_verify(buf, key->dsskey, data_buf);
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_RSA
2020-12-28 21:40:37 +00:00
if (keytype == DROPBEAR_SIGNKEY_RSA) {
2014-12-10 21:56:49 +00:00
if (key->rsakey == NULL) {
dropbear_exit("No RSA key to verify signature");
}
2020-12-28 21:40:37 +00:00
return buf_rsa_verify(buf, key->rsakey, sigtype, data_buf);
2014-12-10 21:56:49 +00:00
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_ECDSA
2020-12-28 21:40:37 +00:00
if (signkey_is_ecdsa(keytype)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
2019-06-09 20:44:26 +00:00
if (eck && *eck) {
2014-12-10 21:56:49 +00:00
return buf_ecdsa_verify(buf, *eck, data_buf);
}
}
#endif
2020-12-28 21:40:37 +00:00
#if DROPBEAR_ED25519
if (keytype == DROPBEAR_SIGNKEY_ED25519) {
if (key->ed25519key == NULL) {
dropbear_exit("No Ed25519 key to verify signature");
}
return buf_ed25519_verify(buf, key->ed25519key, data_buf);
}
#endif
2014-12-10 21:56:49 +00:00
dropbear_exit("Non-matching signing type");
return DROPBEAR_FAILURE;
}
#endif /* DROPBEAR_SIGNKEY_VERIFY */
2019-06-09 20:44:26 +00:00
#if DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
2014-12-10 21:56:49 +00:00
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE when given a buffer containing
* a key, a key, and a type. The buffer is positioned at the start of the
* base64 data, and contains no trailing data */
/* If fingerprint is non-NULL, it will be set to a malloc()ed fingerprint
of the key if it is successfully decoded */
int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
const unsigned char* algoname, unsigned int algolen,
2019-06-09 20:44:26 +00:00
const buffer * line, char ** fingerprint) {
2014-12-10 21:56:49 +00:00
buffer * decodekey = NULL;
int ret = DROPBEAR_FAILURE;
unsigned int len, filealgolen;
unsigned long decodekeylen;
unsigned char* filealgo = NULL;
/* now we have the actual data */
len = line->len - line->pos;
2019-06-09 20:44:26 +00:00
if (len == 0) {
/* base64_decode doesn't like NULL argument */
return DROPBEAR_FAILURE;
}
2014-12-10 21:56:49 +00:00
decodekeylen = len * 2; /* big to be safe */
decodekey = buf_new(decodekeylen);
if (base64_decode(buf_getptr(line, len), len,
buf_getwriteptr(decodekey, decodekey->size),
&decodekeylen) != CRYPT_OK) {
TRACE(("checkpubkey: base64 decode failed"))
goto out;
}
TRACE(("checkpubkey: base64_decode success"))
buf_incrlen(decodekey, decodekeylen);
if (fingerprint) {
*fingerprint = sign_key_fingerprint(buf_getptr(decodekey, decodekeylen),
decodekeylen);
}
/* compare the keys */
if ( ( decodekeylen != keybloblen )
|| memcmp( buf_getptr(decodekey, decodekey->len),
keyblob, decodekey->len) != 0) {
TRACE(("checkpubkey: compare failed"))
goto out;
}
/* ... and also check that the algo specified and the algo in the key
* itself match */
filealgolen = buf_getint(decodekey);
filealgo = buf_getptr(decodekey, filealgolen);
if (filealgolen != algolen || memcmp(filealgo, algoname, algolen) != 0) {
TRACE(("checkpubkey: algo match failed"))
goto out;
}
/* All checks passed */
ret = DROPBEAR_SUCCESS;
out:
buf_free(decodekey);
decodekey = NULL;
return ret;
}
#endif
2019-06-09 20:44:26 +00:00
#if DROPBEAR_FUZZ
const char * const * fuzz_signkey_names = signkey_names;
#endif