version 1.6, 2014/12/10 01:24:09 |
version 1.7, 2014/12/21 22:27:55 |
|
|
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/types.h> |
#include <sys/types.h> |
|
#include <netinet/in.h> |
|
|
#include <openssl/evp.h> |
#include <openssl/evp.h> |
#include <openssl/err.h> |
#include <openssl/err.h> |
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <string.h> |
#include <string.h> |
#include <util.h> |
#include <util.h> |
|
#include <resolv.h> |
|
|
#include "ssh2.h" |
#include "ssh2.h" |
#include "ssherr.h" |
#include "ssherr.h" |
|
|
} |
} |
|
|
int |
int |
sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, |
sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg, |
u_char **retp, size_t *lenp) |
u_char **retp, size_t *lenp) |
{ |
{ |
u_char *blob = NULL, *ret = NULL; |
u_char *blob = NULL, *ret = NULL; |
size_t blob_len = 0; |
size_t blob_len = 0; |
int hash_alg = -1, r = SSH_ERR_INTERNAL_ERROR; |
int r = SSH_ERR_INTERNAL_ERROR; |
|
|
if (retp != NULL) |
if (retp != NULL) |
*retp = NULL; |
*retp = NULL; |
if (lenp != NULL) |
if (lenp != NULL) |
*lenp = 0; |
*lenp = 0; |
|
if (ssh_digest_bytes(dgst_alg) == 0) { |
switch (dgst_type) { |
|
case SSH_FP_MD5: |
|
hash_alg = SSH_DIGEST_MD5; |
|
break; |
|
case SSH_FP_SHA1: |
|
hash_alg = SSH_DIGEST_SHA1; |
|
break; |
|
case SSH_FP_SHA256: |
|
hash_alg = SSH_DIGEST_SHA256; |
|
break; |
|
default: |
|
r = SSH_ERR_INVALID_ARGUMENT; |
r = SSH_ERR_INVALID_ARGUMENT; |
goto out; |
goto out; |
} |
} |
|
|
r = SSH_ERR_ALLOC_FAIL; |
r = SSH_ERR_ALLOC_FAIL; |
goto out; |
goto out; |
} |
} |
if ((r = ssh_digest_memory(hash_alg, blob, blob_len, |
if ((r = ssh_digest_memory(dgst_alg, blob, blob_len, |
ret, SSH_DIGEST_MAX_LENGTH)) != 0) |
ret, SSH_DIGEST_MAX_LENGTH)) != 0) |
goto out; |
goto out; |
/* success */ |
/* success */ |
|
|
ret = NULL; |
ret = NULL; |
} |
} |
if (lenp != NULL) |
if (lenp != NULL) |
*lenp = ssh_digest_bytes(hash_alg); |
*lenp = ssh_digest_bytes(dgst_alg); |
r = 0; |
r = 0; |
out: |
out: |
free(ret); |
free(ret); |
|
|
} |
} |
|
|
static char * |
static char * |
fingerprint_hex(u_char *dgst_raw, size_t dgst_raw_len) |
fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len) |
{ |
{ |
char *retval; |
char *ret; |
size_t i; |
size_t plen = strlen(alg) + 1; |
|
size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1; |
|
int r; |
|
|
if ((retval = calloc(1, dgst_raw_len * 3 + 1)) == NULL) |
if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL) |
return NULL; |
return NULL; |
for (i = 0; i < dgst_raw_len; i++) { |
strlcpy(ret, alg, rlen); |
char hex[4]; |
strlcat(ret, ":", rlen); |
snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]); |
if (dgst_raw_len == 0) |
strlcat(retval, hex, dgst_raw_len * 3 + 1); |
return ret; |
|
if ((r = b64_ntop(dgst_raw, dgst_raw_len, |
|
ret + plen, rlen - plen)) == -1) { |
|
explicit_bzero(ret, rlen); |
|
free(ret); |
|
return NULL; |
} |
} |
|
/* Trim padding characters from end */ |
|
ret[strcspn(ret, "=")] = '\0'; |
|
return ret; |
|
} |
|
|
/* Remove the trailing ':' character */ |
static char * |
retval[(dgst_raw_len * 3) - 1] = '\0'; |
fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len) |
|
{ |
|
char *retval, hex[5]; |
|
size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2; |
|
|
|
if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL) |
|
return NULL; |
|
strlcpy(retval, alg, rlen); |
|
strlcat(retval, ":", rlen); |
|
for (i = 0; i < dgst_raw_len; i++) { |
|
snprintf(hex, sizeof(hex), "%s%02x", |
|
i > 0 ? ":" : "", dgst_raw[i]); |
|
strlcat(retval, hex, rlen); |
|
} |
return retval; |
return retval; |
} |
} |
|
|
|
|
#define FLDSIZE_Y (FLDBASE + 1) |
#define FLDSIZE_Y (FLDBASE + 1) |
#define FLDSIZE_X (FLDBASE * 2 + 1) |
#define FLDSIZE_X (FLDBASE * 2 + 1) |
static char * |
static char * |
fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, |
fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len, |
const struct sshkey *k) |
const struct sshkey *k) |
{ |
{ |
/* |
/* |
|
|
* intersects with itself. Matter of taste. |
* intersects with itself. Matter of taste. |
*/ |
*/ |
char *augmentation_string = " .o+=*BOX@%&#/^SE"; |
char *augmentation_string = " .o+=*BOX@%&#/^SE"; |
char *retval, *p, title[FLDSIZE_X]; |
char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X]; |
u_char field[FLDSIZE_X][FLDSIZE_Y]; |
u_char field[FLDSIZE_X][FLDSIZE_Y]; |
size_t i, tlen; |
size_t i, tlen, hlen; |
u_int b; |
u_int b; |
int x, y, r; |
int x, y, r; |
size_t len = strlen(augmentation_string) - 1; |
size_t len = strlen(augmentation_string) - 1; |
|
|
sshkey_type(k), sshkey_size(k)); |
sshkey_type(k), sshkey_size(k)); |
/* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */ |
/* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */ |
if (r < 0 || r > (int)sizeof(title)) |
if (r < 0 || r > (int)sizeof(title)) |
snprintf(title, sizeof(title), "[%s]", sshkey_type(k)); |
r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k)); |
tlen = strlen(title); |
tlen = (r <= 0) ? 0 : strlen(title); |
|
|
|
/* assemble hash ID. */ |
|
r = snprintf(hash, sizeof(hash), "[%s]", alg); |
|
hlen = (r <= 0) ? 0 : strlen(hash); |
|
|
/* output upper border */ |
/* output upper border */ |
p = retval; |
p = retval; |
*p++ = '+'; |
*p++ = '+'; |
|
|
*p++ = '-'; |
*p++ = '-'; |
memcpy(p, title, tlen); |
memcpy(p, title, tlen); |
p += tlen; |
p += tlen; |
for (i = p - retval - 1; i < FLDSIZE_X; i++) |
for (i += tlen; i < FLDSIZE_X; i++) |
*p++ = '-'; |
*p++ = '-'; |
*p++ = '+'; |
*p++ = '+'; |
*p++ = '\n'; |
*p++ = '\n'; |
|
|
|
|
/* output lower border */ |
/* output lower border */ |
*p++ = '+'; |
*p++ = '+'; |
for (i = 0; i < FLDSIZE_X; i++) |
for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++) |
*p++ = '-'; |
*p++ = '-'; |
|
memcpy(p, hash, hlen); |
|
p += hlen; |
|
for (i += hlen; i < FLDSIZE_X; i++) |
|
*p++ = '-'; |
*p++ = '+'; |
*p++ = '+'; |
|
|
return retval; |
return retval; |
} |
} |
|
|
char * |
char * |
sshkey_fingerprint(const struct sshkey *k, enum sshkey_fp_type dgst_type, |
sshkey_fingerprint(const struct sshkey *k, int dgst_alg, |
enum sshkey_fp_rep dgst_rep) |
enum sshkey_fp_rep dgst_rep) |
{ |
{ |
char *retval = NULL; |
char *retval = NULL; |
u_char *dgst_raw; |
u_char *dgst_raw; |
size_t dgst_raw_len; |
size_t dgst_raw_len; |
|
|
if (sshkey_fingerprint_raw(k, dgst_type, &dgst_raw, &dgst_raw_len) != 0) |
if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0) |
return NULL; |
return NULL; |
switch (dgst_rep) { |
switch (dgst_rep) { |
|
case SSH_FP_DEFAULT: |
|
if (dgst_alg == SSH_DIGEST_MD5) { |
|
retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg), |
|
dgst_raw, dgst_raw_len); |
|
} else { |
|
retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg), |
|
dgst_raw, dgst_raw_len); |
|
} |
|
break; |
case SSH_FP_HEX: |
case SSH_FP_HEX: |
retval = fingerprint_hex(dgst_raw, dgst_raw_len); |
retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg), |
|
dgst_raw, dgst_raw_len); |
break; |
break; |
|
case SSH_FP_BASE64: |
|
retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg), |
|
dgst_raw, dgst_raw_len); |
|
break; |
case SSH_FP_BUBBLEBABBLE: |
case SSH_FP_BUBBLEBABBLE: |
retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len); |
retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len); |
break; |
break; |
case SSH_FP_RANDOMART: |
case SSH_FP_RANDOMART: |
retval = fingerprint_randomart(dgst_raw, dgst_raw_len, k); |
retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg), |
|
dgst_raw, dgst_raw_len, k); |
break; |
break; |
default: |
default: |
explicit_bzero(dgst_raw, dgst_raw_len); |
explicit_bzero(dgst_raw, dgst_raw_len); |