diff options
Diffstat (limited to 'sshkey.c')
-rw-r--r-- | sshkey.c | 113 |
1 files changed, 75 insertions, 38 deletions
@@ -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 | ||
854 | int | 855 | int |
855 | sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, | 856 | sshkey_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 | ||
922 | static char * | 912 | static char * |
923 | fingerprint_hex(u_char *dgst_raw, size_t dgst_raw_len) | 913 | fingerprint_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 */ | 937 | static char * |
937 | retval[(dgst_raw_len * 3) - 1] = '\0'; | 938 | fingerprint_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) |
1022 | static char * | 1036 | static char * |
1023 | fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, | 1037 | fingerprint_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 | ||
1111 | char * | 1133 | char * |
1112 | sshkey_fingerprint(const struct sshkey *k, enum sshkey_fp_type dgst_type, | 1134 | sshkey_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); |