summaryrefslogtreecommitdiff
path: root/sshkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshkey.c')
-rw-r--r--sshkey.c113
1 files changed, 75 insertions, 38 deletions
diff --git a/sshkey.c b/sshkey.c
index cf126626e..a32bd36cc 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshkey.c,v 1.6 2014/12/10 01:24:09 djm Exp $ */ 1/* $OpenBSD: sshkey.c,v 1.7 2014/12/21 22:27:55 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved. 4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@@ -29,6 +29,7 @@
29 29
30#include <sys/param.h> 30#include <sys/param.h>
31#include <sys/types.h> 31#include <sys/types.h>
32#include <netinet/in.h>
32 33
33#include <openssl/evp.h> 34#include <openssl/evp.h>
34#include <openssl/err.h> 35#include <openssl/err.h>
@@ -852,29 +853,18 @@ sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
852} 853}
853 854
854int 855int
855sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, 856sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
856 u_char **retp, size_t *lenp) 857 u_char **retp, size_t *lenp)
857{ 858{
858 u_char *blob = NULL, *ret = NULL; 859 u_char *blob = NULL, *ret = NULL;
859 size_t blob_len = 0; 860 size_t blob_len = 0;
860 int hash_alg = -1, r = SSH_ERR_INTERNAL_ERROR; 861 int r = SSH_ERR_INTERNAL_ERROR;
861 862
862 if (retp != NULL) 863 if (retp != NULL)
863 *retp = NULL; 864 *retp = NULL;
864 if (lenp != NULL) 865 if (lenp != NULL)
865 *lenp = 0; 866 *lenp = 0;
866 867 if (ssh_digest_bytes(dgst_alg) == 0) {
867 switch (dgst_type) {
868 case SSH_FP_MD5:
869 hash_alg = SSH_DIGEST_MD5;
870 break;
871 case SSH_FP_SHA1:
872 hash_alg = SSH_DIGEST_SHA1;
873 break;
874 case SSH_FP_SHA256:
875 hash_alg = SSH_DIGEST_SHA256;
876 break;
877 default:
878 r = SSH_ERR_INVALID_ARGUMENT; 868 r = SSH_ERR_INVALID_ARGUMENT;
879 goto out; 869 goto out;
880 } 870 }
@@ -899,7 +889,7 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type,
899 r = SSH_ERR_ALLOC_FAIL; 889 r = SSH_ERR_ALLOC_FAIL;
900 goto out; 890 goto out;
901 } 891 }
902 if ((r = ssh_digest_memory(hash_alg, blob, blob_len, 892 if ((r = ssh_digest_memory(dgst_alg, blob, blob_len,
903 ret, SSH_DIGEST_MAX_LENGTH)) != 0) 893 ret, SSH_DIGEST_MAX_LENGTH)) != 0)
904 goto out; 894 goto out;
905 /* success */ 895 /* success */
@@ -908,7 +898,7 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type,
908 ret = NULL; 898 ret = NULL;
909 } 899 }
910 if (lenp != NULL) 900 if (lenp != NULL)
911 *lenp = ssh_digest_bytes(hash_alg); 901 *lenp = ssh_digest_bytes(dgst_alg);
912 r = 0; 902 r = 0;
913 out: 903 out:
914 free(ret); 904 free(ret);
@@ -920,21 +910,45 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type,
920} 910}
921 911
922static char * 912static char *
923fingerprint_hex(u_char *dgst_raw, size_t dgst_raw_len) 913fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
924{ 914{
925 char *retval; 915 char *ret;
926 size_t i; 916 size_t plen = strlen(alg) + 1;
917 size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1;
918 int r;
927 919
928 if ((retval = calloc(1, dgst_raw_len * 3 + 1)) == NULL) 920 if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL)
921 return NULL;
922 strlcpy(ret, alg, rlen);
923 strlcat(ret, ":", rlen);
924 if (dgst_raw_len == 0)
925 return ret;
926 if ((r = b64_ntop(dgst_raw, dgst_raw_len,
927 ret + plen, rlen - plen)) == -1) {
928 explicit_bzero(ret, rlen);
929 free(ret);
929 return NULL; 930 return NULL;
930 for (i = 0; i < dgst_raw_len; i++) {
931 char hex[4];
932 snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
933 strlcat(retval, hex, dgst_raw_len * 3 + 1);
934 } 931 }
932 /* Trim padding characters from end */
933 ret[strcspn(ret, "=")] = '\0';
934 return ret;
935}
935 936
936 /* Remove the trailing ':' character */ 937static char *
937 retval[(dgst_raw_len * 3) - 1] = '\0'; 938fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
939{
940 char *retval, hex[5];
941 size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2;
942
943 if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL)
944 return NULL;
945 strlcpy(retval, alg, rlen);
946 strlcat(retval, ":", rlen);
947 for (i = 0; i < dgst_raw_len; i++) {
948 snprintf(hex, sizeof(hex), "%s%02x",
949 i > 0 ? ":" : "", dgst_raw[i]);
950 strlcat(retval, hex, rlen);
951 }
938 return retval; 952 return retval;
939} 953}
940 954
@@ -1020,7 +1034,7 @@ fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
1020#define FLDSIZE_Y (FLDBASE + 1) 1034#define FLDSIZE_Y (FLDBASE + 1)
1021#define FLDSIZE_X (FLDBASE * 2 + 1) 1035#define FLDSIZE_X (FLDBASE * 2 + 1)
1022static char * 1036static char *
1023fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, 1037fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
1024 const struct sshkey *k) 1038 const struct sshkey *k)
1025{ 1039{
1026 /* 1040 /*
@@ -1028,9 +1042,9 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
1028 * intersects with itself. Matter of taste. 1042 * intersects with itself. Matter of taste.
1029 */ 1043 */
1030 char *augmentation_string = " .o+=*BOX@%&#/^SE"; 1044 char *augmentation_string = " .o+=*BOX@%&#/^SE";
1031 char *retval, *p, title[FLDSIZE_X]; 1045 char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
1032 u_char field[FLDSIZE_X][FLDSIZE_Y]; 1046 u_char field[FLDSIZE_X][FLDSIZE_Y];
1033 size_t i, tlen; 1047 size_t i, tlen, hlen;
1034 u_int b; 1048 u_int b;
1035 int x, y, r; 1049 int x, y, r;
1036 size_t len = strlen(augmentation_string) - 1; 1050 size_t len = strlen(augmentation_string) - 1;
@@ -1075,8 +1089,12 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
1075 sshkey_type(k), sshkey_size(k)); 1089 sshkey_type(k), sshkey_size(k));
1076 /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */ 1090 /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
1077 if (r < 0 || r > (int)sizeof(title)) 1091 if (r < 0 || r > (int)sizeof(title))
1078 snprintf(title, sizeof(title), "[%s]", sshkey_type(k)); 1092 r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
1079 tlen = strlen(title); 1093 tlen = (r <= 0) ? 0 : strlen(title);
1094
1095 /* assemble hash ID. */
1096 r = snprintf(hash, sizeof(hash), "[%s]", alg);
1097 hlen = (r <= 0) ? 0 : strlen(hash);
1080 1098
1081 /* output upper border */ 1099 /* output upper border */
1082 p = retval; 1100 p = retval;
@@ -1085,7 +1103,7 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
1085 *p++ = '-'; 1103 *p++ = '-';
1086 memcpy(p, title, tlen); 1104 memcpy(p, title, tlen);
1087 p += tlen; 1105 p += tlen;
1088 for (i = p - retval - 1; i < FLDSIZE_X; i++) 1106 for (i += tlen; i < FLDSIZE_X; i++)
1089 *p++ = '-'; 1107 *p++ = '-';
1090 *p++ = '+'; 1108 *p++ = '+';
1091 *p++ = '\n'; 1109 *p++ = '\n';
@@ -1101,7 +1119,11 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
1101 1119
1102 /* output lower border */ 1120 /* output lower border */
1103 *p++ = '+'; 1121 *p++ = '+';
1104 for (i = 0; i < FLDSIZE_X; i++) 1122 for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
1123 *p++ = '-';
1124 memcpy(p, hash, hlen);
1125 p += hlen;
1126 for (i += hlen; i < FLDSIZE_X; i++)
1105 *p++ = '-'; 1127 *p++ = '-';
1106 *p++ = '+'; 1128 *p++ = '+';
1107 1129
@@ -1109,24 +1131,39 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
1109} 1131}
1110 1132
1111char * 1133char *
1112sshkey_fingerprint(const struct sshkey *k, enum sshkey_fp_type dgst_type, 1134sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
1113 enum sshkey_fp_rep dgst_rep) 1135 enum sshkey_fp_rep dgst_rep)
1114{ 1136{
1115 char *retval = NULL; 1137 char *retval = NULL;
1116 u_char *dgst_raw; 1138 u_char *dgst_raw;
1117 size_t dgst_raw_len; 1139 size_t dgst_raw_len;
1118 1140
1119 if (sshkey_fingerprint_raw(k, dgst_type, &dgst_raw, &dgst_raw_len) != 0) 1141 if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0)
1120 return NULL; 1142 return NULL;
1121 switch (dgst_rep) { 1143 switch (dgst_rep) {
1144 case SSH_FP_DEFAULT:
1145 if (dgst_alg == SSH_DIGEST_MD5) {
1146 retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1147 dgst_raw, dgst_raw_len);
1148 } else {
1149 retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1150 dgst_raw, dgst_raw_len);
1151 }
1152 break;
1122 case SSH_FP_HEX: 1153 case SSH_FP_HEX:
1123 retval = fingerprint_hex(dgst_raw, dgst_raw_len); 1154 retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1155 dgst_raw, dgst_raw_len);
1156 break;
1157 case SSH_FP_BASE64:
1158 retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1159 dgst_raw, dgst_raw_len);
1124 break; 1160 break;
1125 case SSH_FP_BUBBLEBABBLE: 1161 case SSH_FP_BUBBLEBABBLE:
1126 retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len); 1162 retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
1127 break; 1163 break;
1128 case SSH_FP_RANDOMART: 1164 case SSH_FP_RANDOMART:
1129 retval = fingerprint_randomart(dgst_raw, dgst_raw_len, k); 1165 retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg),
1166 dgst_raw, dgst_raw_len, k);
1130 break; 1167 break;
1131 default: 1168 default:
1132 explicit_bzero(dgst_raw, dgst_raw_len); 1169 explicit_bzero(dgst_raw, dgst_raw_len);