| 1 |  |  | /* $OpenBSD: key.c,v 1.131 2017/05/30 14:16:41 markus Exp $ */ | 
    
    | 2 |  |  | /* | 
    
    | 3 |  |  |  * placed in the public domain | 
    
    | 4 |  |  |  */ | 
    
    | 5 |  |  |  | 
    
    | 6 |  |  | #include <sys/types.h> | 
    
    | 7 |  |  | #include <errno.h> | 
    
    | 8 |  |  | #include <stdarg.h> | 
    
    | 9 |  |  | #include <stdio.h> | 
    
    | 10 |  |  | #include <limits.h> | 
    
    | 11 |  |  |  | 
    
    | 12 |  |  | #define SSH_KEY_NO_DEFINE | 
    
    | 13 |  |  | #include "key.h" | 
    
    | 14 |  |  |  | 
    
    | 15 |  |  | #include "compat.h" | 
    
    | 16 |  |  | #include "sshkey.h" | 
    
    | 17 |  |  | #include "ssherr.h" | 
    
    | 18 |  |  | #include "log.h" | 
    
    | 19 |  |  | #include "authfile.h" | 
    
    | 20 |  |  |  | 
    
    | 21 |  |  | static void | 
    
    | 22 |  |  | fatal_on_fatal_errors(int r, const char *func, int extra_fatal) | 
    
    | 23 |  |  | { | 
    
    | 24 | ✓✗✗✓ 
 | 144 | 	if (r == SSH_ERR_INTERNAL_ERROR || | 
    
    | 25 |  | 36 | 	    r == SSH_ERR_ALLOC_FAIL || | 
    
    | 26 | ✓✗ | 72 | 	    (extra_fatal != 0 && r == extra_fatal)) | 
    
    | 27 |  |  | 		fatal("%s: %s", func, ssh_err(r)); | 
    
    | 28 |  | 36 | } | 
    
    | 29 |  |  |  | 
    
    | 30 |  |  | Key * | 
    
    | 31 |  |  | key_from_blob(const u_char *blob, u_int blen) | 
    
    | 32 |  |  | { | 
    
    | 33 |  |  | 	int r; | 
    
    | 34 |  |  | 	Key *ret = NULL; | 
    
    | 35 |  |  |  | 
    
    | 36 |  |  | 	if ((r = sshkey_from_blob(blob, blen, &ret)) != 0) { | 
    
    | 37 |  |  | 		fatal_on_fatal_errors(r, __func__, 0); | 
    
    | 38 |  |  | 		error("%s: %s", __func__, ssh_err(r)); | 
    
    | 39 |  |  | 		return NULL; | 
    
    | 40 |  |  | 	} | 
    
    | 41 |  |  | 	return ret; | 
    
    | 42 |  |  | } | 
    
    | 43 |  |  |  | 
    
    | 44 |  |  | int | 
    
    | 45 |  |  | key_to_blob(const Key *key, u_char **blobp, u_int *lenp) | 
    
    | 46 |  |  | { | 
    
    | 47 |  |  | 	u_char *blob; | 
    
    | 48 |  |  | 	size_t blen; | 
    
    | 49 |  |  | 	int r; | 
    
    | 50 |  |  |  | 
    
    | 51 |  |  | 	if (blobp != NULL) | 
    
    | 52 |  |  | 		*blobp = NULL; | 
    
    | 53 |  |  | 	if (lenp != NULL) | 
    
    | 54 |  |  | 		*lenp = 0; | 
    
    | 55 |  |  | 	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) { | 
    
    | 56 |  |  | 		fatal_on_fatal_errors(r, __func__, 0); | 
    
    | 57 |  |  | 		error("%s: %s", __func__, ssh_err(r)); | 
    
    | 58 |  |  | 		return 0; | 
    
    | 59 |  |  | 	} | 
    
    | 60 |  |  | 	if (blen > INT_MAX) | 
    
    | 61 |  |  | 		fatal("%s: giant len %zu", __func__, blen); | 
    
    | 62 |  |  | 	if (blobp != NULL) | 
    
    | 63 |  |  | 		*blobp = blob; | 
    
    | 64 |  |  | 	if (lenp != NULL) | 
    
    | 65 |  |  | 		*lenp = blen; | 
    
    | 66 |  |  | 	return blen; | 
    
    | 67 |  |  | } | 
    
    | 68 |  |  |  | 
    
    | 69 |  |  | int | 
    
    | 70 |  |  | key_sign(const Key *key, u_char **sigp, u_int *lenp, | 
    
    | 71 |  |  |     const u_char *data, u_int datalen, const char *alg) | 
    
    | 72 |  |  | { | 
    
    | 73 |  |  | 	int r; | 
    
    | 74 |  |  | 	u_char *sig; | 
    
    | 75 |  |  | 	size_t siglen; | 
    
    | 76 |  |  |  | 
    
    | 77 |  |  | 	if (sigp != NULL) | 
    
    | 78 |  |  | 		*sigp = NULL; | 
    
    | 79 |  |  | 	if (lenp != NULL) | 
    
    | 80 |  |  | 		*lenp = 0; | 
    
    | 81 |  |  | 	if ((r = sshkey_sign(key, &sig, &siglen, | 
    
    | 82 |  |  | 	    data, datalen, alg, datafellows)) != 0) { | 
    
    | 83 |  |  | 		fatal_on_fatal_errors(r, __func__, 0); | 
    
    | 84 |  |  | 		error("%s: %s", __func__, ssh_err(r)); | 
    
    | 85 |  |  | 		return -1; | 
    
    | 86 |  |  | 	} | 
    
    | 87 |  |  | 	if (siglen > INT_MAX) | 
    
    | 88 |  |  | 		fatal("%s: giant len %zu", __func__, siglen); | 
    
    | 89 |  |  | 	if (sigp != NULL) | 
    
    | 90 |  |  | 		*sigp = sig; | 
    
    | 91 |  |  | 	if (lenp != NULL) | 
    
    | 92 |  |  | 		*lenp = siglen; | 
    
    | 93 |  |  | 	return 0; | 
    
    | 94 |  |  | } | 
    
    | 95 |  |  |  | 
    
    | 96 |  |  | int | 
    
    | 97 |  |  | key_verify(const Key *key, const u_char *signature, u_int signaturelen, | 
    
    | 98 |  |  |     const u_char *data, u_int datalen) | 
    
    | 99 |  |  | { | 
    
    | 100 |  |  | 	int r; | 
    
    | 101 |  |  |  | 
    
    | 102 |  |  | 	if ((r = sshkey_verify(key, signature, signaturelen, | 
    
    | 103 |  |  | 	    data, datalen, datafellows)) != 0) { | 
    
    | 104 |  |  | 		fatal_on_fatal_errors(r, __func__, 0); | 
    
    | 105 |  |  | 		error("%s: %s", __func__, ssh_err(r)); | 
    
    | 106 |  |  | 		return r == SSH_ERR_SIGNATURE_INVALID ? 0 : -1; | 
    
    | 107 |  |  | 	} | 
    
    | 108 |  |  | 	return 1; | 
    
    | 109 |  |  | } | 
    
    | 110 |  |  |  | 
    
    | 111 |  |  | Key * | 
    
    | 112 |  |  | key_demote(const Key *k) | 
    
    | 113 |  |  | { | 
    
    | 114 |  |  | 	int r; | 
    
    | 115 |  | 56 | 	Key *ret = NULL; | 
    
    | 116 |  |  |  | 
    
    | 117 | ✗✓ | 28 | 	if ((r = sshkey_demote(k, &ret)) != 0) | 
    
    | 118 |  |  | 		fatal("%s: %s", __func__, ssh_err(r)); | 
    
    | 119 |  | 56 | 	return ret; | 
    
    | 120 |  | 28 | } | 
    
    | 121 |  |  |  | 
    
    | 122 |  |  | int | 
    
    | 123 |  |  | key_drop_cert(Key *k) | 
    
    | 124 |  |  | { | 
    
    | 125 |  |  | 	int r; | 
    
    | 126 |  |  |  | 
    
    | 127 |  |  | 	if ((r = sshkey_drop_cert(k)) != 0) { | 
    
    | 128 |  |  | 		fatal_on_fatal_errors(r, __func__, 0); | 
    
    | 129 |  |  | 		error("%s: %s", __func__, ssh_err(r)); | 
    
    | 130 |  |  | 		return -1; | 
    
    | 131 |  |  | 	} | 
    
    | 132 |  |  | 	return 0; | 
    
    | 133 |  |  | } | 
    
    | 134 |  |  |  | 
    
    | 135 |  |  | int | 
    
    | 136 |  |  | key_cert_check_authority(const Key *k, int want_host, int require_principal, | 
    
    | 137 |  |  |     const char *name, const char **reason) | 
    
    | 138 |  |  | { | 
    
    | 139 |  |  | 	int r; | 
    
    | 140 |  |  |  | 
    
    | 141 |  |  | 	if ((r = sshkey_cert_check_authority(k, want_host, require_principal, | 
    
    | 142 |  |  | 	    name, reason)) != 0) { | 
    
    | 143 |  |  | 		fatal_on_fatal_errors(r, __func__, 0); | 
    
    | 144 |  |  | 		error("%s: %s", __func__, ssh_err(r)); | 
    
    | 145 |  |  | 		return -1; | 
    
    | 146 |  |  | 	} | 
    
    | 147 |  |  | 	return 0; | 
    
    | 148 |  |  | } | 
    
    | 149 |  |  |  | 
    
    | 150 |  |  | /* authfile.c */ | 
    
    | 151 |  |  |  | 
    
    | 152 |  |  | Key * | 
    
    | 153 |  |  | key_load_cert(const char *filename) | 
    
    | 154 |  |  | { | 
    
    | 155 |  |  | 	int r; | 
    
    | 156 |  |  | 	Key *ret = NULL; | 
    
    | 157 |  |  |  | 
    
    | 158 |  |  | 	if ((r = sshkey_load_cert(filename, &ret)) != 0) { | 
    
    | 159 |  |  | 		fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); | 
    
    | 160 |  |  | 		/* Old authfile.c ignored all file errors. */ | 
    
    | 161 |  |  | 		if (r == SSH_ERR_SYSTEM_ERROR) | 
    
    | 162 |  |  | 			debug("%s: %s", __func__, ssh_err(r)); | 
    
    | 163 |  |  | 		else | 
    
    | 164 |  |  | 			error("%s: %s", __func__, ssh_err(r)); | 
    
    | 165 |  |  | 		return NULL; | 
    
    | 166 |  |  | 	} | 
    
    | 167 |  |  | 	return ret; | 
    
    | 168 |  |  |  | 
    
    | 169 |  |  | } | 
    
    | 170 |  |  |  | 
    
    | 171 |  |  | Key * | 
    
    | 172 |  |  | key_load_public(const char *filename, char **commentp) | 
    
    | 173 |  |  | { | 
    
    | 174 |  |  | 	int r; | 
    
    | 175 |  | 100 | 	Key *ret = NULL; | 
    
    | 176 |  |  |  | 
    
    | 177 | ✓✓ | 50 | 	if ((r = sshkey_load_public(filename, &ret, commentp)) != 0) { | 
    
    | 178 |  | 36 | 		fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); | 
    
    | 179 |  |  | 		/* Old authfile.c ignored all file errors. */ | 
    
    | 180 | ✓✗ | 72 | 		if (r == SSH_ERR_SYSTEM_ERROR) | 
    
    | 181 |  | 72 | 			debug("%s: %s", __func__, ssh_err(r)); | 
    
    | 182 |  |  | 		else | 
    
    | 183 |  |  | 			error("%s: %s", __func__, ssh_err(r)); | 
    
    | 184 |  | 36 | 		return NULL; | 
    
    | 185 |  |  | 	} | 
    
    | 186 |  | 14 | 	return ret; | 
    
    | 187 |  | 50 | } | 
    
    | 188 |  |  |  | 
    
    | 189 |  |  | Key * | 
    
    | 190 |  |  | key_load_private(const char *path, const char *passphrase, | 
    
    | 191 |  |  |     char **commentp) | 
    
    | 192 |  |  | { | 
    
    | 193 |  |  | 	int r; | 
    
    | 194 |  | 84 | 	Key *ret = NULL; | 
    
    | 195 |  |  |  | 
    
    | 196 | ✗✓ | 42 | 	if ((r = sshkey_load_private(path, passphrase, &ret, commentp)) != 0) { | 
    
    | 197 |  |  | 		fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); | 
    
    | 198 |  |  | 		/* Old authfile.c ignored all file errors. */ | 
    
    | 199 |  |  | 		if (r == SSH_ERR_SYSTEM_ERROR || | 
    
    | 200 |  |  | 		    r == SSH_ERR_KEY_WRONG_PASSPHRASE) | 
    
    | 201 |  |  | 			debug("%s: %s", __func__, ssh_err(r)); | 
    
    | 202 |  |  | 		else | 
    
    | 203 |  |  | 			error("%s: %s", __func__, ssh_err(r)); | 
    
    | 204 |  |  | 		return NULL; | 
    
    | 205 |  |  | 	} | 
    
    | 206 |  | 42 | 	return ret; | 
    
    | 207 |  | 42 | } | 
    
    | 208 |  |  |  | 
    
    | 209 |  |  | Key * | 
    
    | 210 |  |  | key_load_private_cert(int type, const char *filename, const char *passphrase, | 
    
    | 211 |  |  |     int *perm_ok) | 
    
    | 212 |  |  | { | 
    
    | 213 |  |  | 	int r; | 
    
    | 214 |  |  | 	Key *ret = NULL; | 
    
    | 215 |  |  |  | 
    
    | 216 |  |  | 	if ((r = sshkey_load_private_cert(type, filename, passphrase, | 
    
    | 217 |  |  | 	    &ret, perm_ok)) != 0) { | 
    
    | 218 |  |  | 		fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); | 
    
    | 219 |  |  | 		/* Old authfile.c ignored all file errors. */ | 
    
    | 220 |  |  | 		if (r == SSH_ERR_SYSTEM_ERROR || | 
    
    | 221 |  |  | 		    r == SSH_ERR_KEY_WRONG_PASSPHRASE) | 
    
    | 222 |  |  | 			debug("%s: %s", __func__, ssh_err(r)); | 
    
    | 223 |  |  | 		else | 
    
    | 224 |  |  | 			error("%s: %s", __func__, ssh_err(r)); | 
    
    | 225 |  |  | 		return NULL; | 
    
    | 226 |  |  | 	} | 
    
    | 227 |  |  | 	return ret; | 
    
    | 228 |  |  | } | 
    
    | 229 |  |  |  | 
    
    | 230 |  |  | Key * | 
    
    | 231 |  |  | key_load_private_type(int type, const char *filename, const char *passphrase, | 
    
    | 232 |  |  |     char **commentp, int *perm_ok) | 
    
    | 233 |  |  | { | 
    
    | 234 |  |  | 	int r; | 
    
    | 235 |  |  | 	Key *ret = NULL; | 
    
    | 236 |  |  |  | 
    
    | 237 |  |  | 	if ((r = sshkey_load_private_type(type, filename, passphrase, | 
    
    | 238 |  |  | 	    &ret, commentp, perm_ok)) != 0) { | 
    
    | 239 |  |  | 		fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); | 
    
    | 240 |  |  | 		/* Old authfile.c ignored all file errors. */ | 
    
    | 241 |  |  | 		if (r == SSH_ERR_SYSTEM_ERROR || | 
    
    | 242 |  |  | 		    (r == SSH_ERR_KEY_WRONG_PASSPHRASE)) | 
    
    | 243 |  |  | 			debug("%s: %s", __func__, ssh_err(r)); | 
    
    | 244 |  |  | 		else | 
    
    | 245 |  |  | 			error("%s: %s", __func__, ssh_err(r)); | 
    
    | 246 |  |  | 		return NULL; | 
    
    | 247 |  |  | 	} | 
    
    | 248 |  |  | 	return ret; | 
    
    | 249 |  |  | } |