| /* $OpenBSD: key.c,v 1.120 2014/07/09 03:02:15 djm Exp $ */ |
| /* |
| * placed in the public domain |
| */ |
| |
| #include "includes.h" |
| |
| #include <sys/param.h> |
| #include <sys/types.h> |
| #include <errno.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| |
| #define SSH_KEY_NO_DEFINE |
| #include "key.h" |
| |
| #include "compat.h" |
| #include "sshkey.h" |
| #include "ssherr.h" |
| #include "log.h" |
| #include "authfile.h" |
| |
| void |
| key_add_private(Key *k) |
| { |
| int r; |
| |
| if ((r = sshkey_add_private(k)) != 0) |
| fatal("%s: %s", __func__, ssh_err(r)); |
| } |
| |
| Key * |
| key_new_private(int type) |
| { |
| Key *ret = NULL; |
| |
| if ((ret = sshkey_new_private(type)) == NULL) |
| fatal("%s: failed", __func__); |
| return ret; |
| } |
| |
| u_char* |
| key_fingerprint_raw(const Key *k, enum fp_type dgst_type, |
| u_int *dgst_raw_length) |
| { |
| u_char *ret = NULL; |
| size_t dlen; |
| int r; |
| |
| if (dgst_raw_length != NULL) |
| *dgst_raw_length = 0; |
| if ((r = sshkey_fingerprint_raw(k, dgst_type, &ret, &dlen)) != 0) |
| fatal("%s: %s", __func__, ssh_err(r)); |
| if (dlen > INT_MAX) |
| fatal("%s: giant len %zu", __func__, dlen); |
| *dgst_raw_length = dlen; |
| return ret; |
| } |
| |
| int |
| key_read(Key *ret, char **cpp) |
| { |
| return sshkey_read(ret, cpp) == 0 ? 1 : -1; |
| } |
| |
| int |
| key_write(const Key *key, FILE *f) |
| { |
| return sshkey_write(key, f) == 0 ? 1 : 0; |
| } |
| |
| Key * |
| key_generate(int type, u_int bits) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_generate(type, bits, &ret)) != 0) |
| fatal("%s: %s", __func__, ssh_err(r)); |
| return ret; |
| } |
| |
| void |
| key_cert_copy(const Key *from_key, Key *to_key) |
| { |
| int r; |
| |
| if ((r = sshkey_cert_copy(from_key, to_key)) != 0) |
| fatal("%s: %s", __func__, ssh_err(r)); |
| } |
| |
| Key * |
| key_from_private(const Key *k) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_from_private(k, &ret)) != 0) |
| fatal("%s: %s", __func__, ssh_err(r)); |
| return ret; |
| } |
| |
| static void |
| fatal_on_fatal_errors(int r, const char *func, int extra_fatal) |
| { |
| if (r == SSH_ERR_INTERNAL_ERROR || |
| r == SSH_ERR_ALLOC_FAIL || |
| (extra_fatal != 0 && r == extra_fatal)) |
| fatal("%s: %s", func, ssh_err(r)); |
| } |
| |
| Key * |
| key_from_blob(const u_char *blob, u_int blen) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_from_blob(blob, blen, &ret)) != 0) { |
| fatal_on_fatal_errors(r, __func__, 0); |
| error("%s: %s", __func__, ssh_err(r)); |
| return NULL; |
| } |
| return ret; |
| } |
| |
| int |
| key_to_blob(const Key *key, u_char **blobp, u_int *lenp) |
| { |
| u_char *blob; |
| size_t blen; |
| int r; |
| |
| if (blobp != NULL) |
| *blobp = NULL; |
| if (lenp != NULL) |
| *lenp = 0; |
| if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) { |
| fatal_on_fatal_errors(r, __func__, 0); |
| error("%s: %s", __func__, ssh_err(r)); |
| return 0; |
| } |
| if (blen > INT_MAX) |
| fatal("%s: giant len %zu", __func__, blen); |
| if (blobp != NULL) |
| *blobp = blob; |
| if (lenp != NULL) |
| *lenp = blen; |
| return blen; |
| } |
| |
| int |
| key_sign(const Key *key, u_char **sigp, u_int *lenp, |
| const u_char *data, u_int datalen) |
| { |
| int r; |
| u_char *sig; |
| size_t siglen; |
| |
| if (sigp != NULL) |
| *sigp = NULL; |
| if (lenp != NULL) |
| *lenp = 0; |
| if ((r = sshkey_sign(key, &sig, &siglen, |
| data, datalen, datafellows)) != 0) { |
| fatal_on_fatal_errors(r, __func__, 0); |
| error("%s: %s", __func__, ssh_err(r)); |
| return -1; |
| } |
| if (siglen > INT_MAX) |
| fatal("%s: giant len %zu", __func__, siglen); |
| if (sigp != NULL) |
| *sigp = sig; |
| if (lenp != NULL) |
| *lenp = siglen; |
| return 0; |
| } |
| |
| int |
| key_verify(const Key *key, const u_char *signature, u_int signaturelen, |
| const u_char *data, u_int datalen) |
| { |
| int r; |
| |
| if ((r = sshkey_verify(key, signature, signaturelen, |
| data, datalen, datafellows)) != 0) { |
| fatal_on_fatal_errors(r, __func__, 0); |
| error("%s: %s", __func__, ssh_err(r)); |
| return r == SSH_ERR_SIGNATURE_INVALID ? 0 : -1; |
| } |
| return 1; |
| } |
| |
| Key * |
| key_demote(const Key *k) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_demote(k, &ret)) != 0) |
| fatal("%s: %s", __func__, ssh_err(r)); |
| return ret; |
| } |
| |
| int |
| key_to_certified(Key *k, int legacy) |
| { |
| int r; |
| |
| if ((r = sshkey_to_certified(k, legacy)) != 0) { |
| fatal_on_fatal_errors(r, __func__, 0); |
| error("%s: %s", __func__, ssh_err(r)); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int |
| key_drop_cert(Key *k) |
| { |
| int r; |
| |
| if ((r = sshkey_drop_cert(k)) != 0) { |
| fatal_on_fatal_errors(r, __func__, 0); |
| error("%s: %s", __func__, ssh_err(r)); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int |
| key_certify(Key *k, Key *ca) |
| { |
| int r; |
| |
| if ((r = sshkey_certify(k, ca)) != 0) { |
| fatal_on_fatal_errors(r, __func__, 0); |
| error("%s: %s", __func__, ssh_err(r)); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int |
| key_cert_check_authority(const Key *k, int want_host, int require_principal, |
| const char *name, const char **reason) |
| { |
| int r; |
| |
| if ((r = sshkey_cert_check_authority(k, want_host, require_principal, |
| name, reason)) != 0) { |
| fatal_on_fatal_errors(r, __func__, 0); |
| error("%s: %s", __func__, ssh_err(r)); |
| return -1; |
| } |
| return 0; |
| } |
| |
| #ifdef WITH_OPENSSL |
| int |
| key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) |
| { |
| int r; |
| |
| if ((r = sshkey_ec_validate_public(group, public)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| error("%s: %s", __func__, ssh_err(r)); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int |
| key_ec_validate_private(const EC_KEY *key) |
| { |
| int r; |
| |
| if ((r = sshkey_ec_validate_private(key)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| error("%s: %s", __func__, ssh_err(r)); |
| return -1; |
| } |
| return 0; |
| } |
| #endif /* WITH_OPENSSL */ |
| |
| void |
| key_private_serialize(const Key *key, struct sshbuf *b) |
| { |
| int r; |
| |
| if ((r = sshkey_private_serialize(key, b)) != 0) |
| fatal("%s: %s", __func__, ssh_err(r)); |
| } |
| |
| Key * |
| key_private_deserialize(struct sshbuf *blob) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_private_deserialize(blob, &ret)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| error("%s: %s", __func__, ssh_err(r)); |
| return NULL; |
| } |
| return ret; |
| } |
| |
| /* authfile.c */ |
| |
| int |
| key_save_private(Key *key, const char *filename, const char *passphrase, |
| const char *comment, int force_new_format, const char *new_format_cipher, |
| int new_format_rounds) |
| { |
| int r; |
| |
| if ((r = sshkey_save_private(key, filename, passphrase, comment, |
| force_new_format, new_format_cipher, new_format_rounds)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| error("%s: %s", __func__, ssh_err(r)); |
| return 0; |
| } |
| return 1; |
| } |
| |
| int |
| key_load_file(int fd, const char *filename, struct sshbuf *blob) |
| { |
| int r; |
| |
| if ((r = sshkey_load_file(fd, filename, blob)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| error("%s: %s", __func__, ssh_err(r)); |
| return 0; |
| } |
| return 1; |
| } |
| |
| Key * |
| key_load_cert(const char *filename) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_load_cert(filename, &ret)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| /* Old authfile.c ignored all file errors. */ |
| if (r == SSH_ERR_SYSTEM_ERROR) |
| debug("%s: %s", __func__, ssh_err(r)); |
| else |
| error("%s: %s", __func__, ssh_err(r)); |
| return NULL; |
| } |
| return ret; |
| |
| } |
| |
| Key * |
| key_load_public(const char *filename, char **commentp) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_load_public(filename, &ret, commentp)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| /* Old authfile.c ignored all file errors. */ |
| if (r == SSH_ERR_SYSTEM_ERROR) |
| debug("%s: %s", __func__, ssh_err(r)); |
| else |
| error("%s: %s", __func__, ssh_err(r)); |
| return NULL; |
| } |
| return ret; |
| } |
| |
| Key * |
| key_load_private(const char *path, const char *passphrase, |
| char **commentp) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_load_private(path, passphrase, &ret, commentp)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| /* Old authfile.c ignored all file errors. */ |
| if (r == SSH_ERR_SYSTEM_ERROR) |
| debug("%s: %s", __func__, ssh_err(r)); |
| else |
| error("%s: %s", __func__, ssh_err(r)); |
| return NULL; |
| } |
| return ret; |
| } |
| |
| Key * |
| key_load_private_cert(int type, const char *filename, const char *passphrase, |
| int *perm_ok) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_load_private_cert(type, filename, passphrase, |
| &ret, perm_ok)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| /* Old authfile.c ignored all file errors. */ |
| if (r == SSH_ERR_SYSTEM_ERROR) |
| debug("%s: %s", __func__, ssh_err(r)); |
| else |
| error("%s: %s", __func__, ssh_err(r)); |
| return NULL; |
| } |
| return ret; |
| } |
| |
| Key * |
| key_load_private_type(int type, const char *filename, const char *passphrase, |
| char **commentp, int *perm_ok) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_load_private_type(type, filename, passphrase, |
| &ret, commentp, perm_ok)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| /* Old authfile.c ignored all file errors. */ |
| if (r == SSH_ERR_SYSTEM_ERROR || |
| (r == SSH_ERR_KEY_WRONG_PASSPHRASE)) |
| debug("%s: %s", __func__, ssh_err(r)); |
| else |
| error("%s: %s", __func__, ssh_err(r)); |
| return NULL; |
| } |
| return ret; |
| } |
| |
| #ifdef WITH_OPENSSL |
| Key * |
| key_load_private_pem(int fd, int type, const char *passphrase, |
| char **commentp) |
| { |
| int r; |
| Key *ret = NULL; |
| |
| if ((r = sshkey_load_private_pem(fd, type, passphrase, |
| &ret, commentp)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| error("%s: %s", __func__, ssh_err(r)); |
| return NULL; |
| } |
| return ret; |
| } |
| #endif /* WITH_OPENSSL */ |
| |
| int |
| key_perm_ok(int fd, const char *filename) |
| { |
| return sshkey_perm_ok(fd, filename) == 0 ? 1 : 0; |
| } |
| |
| int |
| key_in_file(Key *key, const char *filename, int strict_type) |
| { |
| int r; |
| |
| if ((r = sshkey_in_file(key, filename, strict_type)) != 0) { |
| fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
| if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) |
| return 0; |
| error("%s: %s", __func__, ssh_err(r)); |
| return r == SSH_ERR_KEY_NOT_FOUND ? 0 : -1; |
| } |
| return 1; |
| } |