=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-ed25519.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- src/usr.bin/ssh/ssh-ed25519.c 2014/02/23 20:03:42 1.3 +++ src/usr.bin/ssh/ssh-ed25519.c 2014/06/24 01:13:21 1.4 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-ed25519.c,v 1.3 2014/02/23 20:03:42 djm Exp $ */ +/* $OpenBSD: ssh-ed25519.c,v 1.4 2014/06/24 01:13:21 djm Exp $ */ /* * Copyright (c) 2013 Markus Friedl * @@ -14,134 +14,150 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - +#define SSHKEY_INTERNAL #include +#include #include "crypto_api.h" -#include #include #include #include "xmalloc.h" #include "log.h" #include "buffer.h" -#include "key.h" +#include "sshkey.h" +#include "ssherr.h" #include "ssh.h" int -ssh_ed25519_sign(const Key *key, u_char **sigp, u_int *lenp, - const u_char *data, u_int datalen) +ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, u_int compat) { - u_char *sig; - u_int slen, len; + u_char *sig = NULL; + size_t slen = 0, len; unsigned long long smlen; - int ret; - Buffer b; + int r, ret; + struct sshbuf *b = NULL; - if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || - key->ed25519_sk == NULL) { - error("%s: no ED25519 key", __func__); - return -1; - } + if (lenp != NULL) + *lenp = 0; + if (sigp != NULL) + *sigp = NULL; - if (datalen >= UINT_MAX - crypto_sign_ed25519_BYTES) { - error("%s: datalen %u too long", __func__, datalen); - return -1; - } + if (key == NULL || + sshkey_type_plain(key->type) != KEY_ED25519 || + key->ed25519_sk == NULL || + datalen >= INT_MAX - crypto_sign_ed25519_BYTES) + return SSH_ERR_INVALID_ARGUMENT; smlen = slen = datalen + crypto_sign_ed25519_BYTES; - sig = xmalloc(slen); + if ((sig = malloc(slen)) == NULL) + return SSH_ERR_ALLOC_FAIL; if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, key->ed25519_sk)) != 0 || smlen <= datalen) { - error("%s: crypto_sign_ed25519 failed: %d", __func__, ret); - free(sig); - return -1; + r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ + goto out; } /* encode signature */ - buffer_init(&b); - buffer_put_cstring(&b, "ssh-ed25519"); - buffer_put_string(&b, sig, smlen - datalen); - len = buffer_len(&b); + if ((b = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || + (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) + goto out; + len = sshbuf_len(b); + if (sigp != NULL) { + if ((*sigp = malloc(len)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + memcpy(*sigp, sshbuf_ptr(b), len); + } if (lenp != NULL) *lenp = len; - if (sigp != NULL) { - *sigp = xmalloc(len); - memcpy(*sigp, buffer_ptr(&b), len); + /* success */ + r = 0; + out: + sshbuf_free(b); + if (sig != NULL) { + explicit_bzero(sig, slen); + free(sig); } - buffer_free(&b); - explicit_bzero(sig, slen); - free(sig); - return 0; + return r; } int -ssh_ed25519_verify(const Key *key, const u_char *signature, u_int signaturelen, - const u_char *data, u_int datalen) +ssh_ed25519_verify(const struct sshkey *key, + const u_char *signature, size_t signaturelen, + const u_char *data, size_t datalen, u_int compat) { - Buffer b; - char *ktype; - u_char *sigblob, *sm, *m; - u_int len; - unsigned long long smlen, mlen; - int rlen, ret; + struct sshbuf *b = NULL; + char *ktype = NULL; + const u_char *sigblob; + u_char *sm = NULL, *m = NULL; + size_t len; + unsigned long long smlen = 0, mlen = 0; + int r, ret; - if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || - key->ed25519_pk == NULL) { - error("%s: no ED25519 key", __func__); - return -1; - } - buffer_init(&b); - buffer_append(&b, signature, signaturelen); - ktype = buffer_get_cstring(&b, NULL); + if (key == NULL || + sshkey_type_plain(key->type) != KEY_ED25519 || + key->ed25519_pk == NULL || + datalen >= INT_MAX - crypto_sign_ed25519_BYTES) + return SSH_ERR_INVALID_ARGUMENT; + + if ((b = sshbuf_from(signature, signaturelen)) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || + (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) + goto out; if (strcmp("ssh-ed25519", ktype) != 0) { - error("%s: cannot handle type %s", __func__, ktype); - buffer_free(&b); - free(ktype); - return -1; + r = SSH_ERR_KEY_TYPE_MISMATCH; + goto out; } - free(ktype); - sigblob = buffer_get_string(&b, &len); - rlen = buffer_len(&b); - buffer_free(&b); - if (rlen != 0) { - error("%s: remaining bytes in signature %d", __func__, rlen); - free(sigblob); - return -1; + if (sshbuf_len(b) != 0) { + r = SSH_ERR_UNEXPECTED_TRAILING_DATA; + goto out; } if (len > crypto_sign_ed25519_BYTES) { - error("%s: len %u > crypto_sign_ed25519_BYTES %u", __func__, - len, crypto_sign_ed25519_BYTES); - free(sigblob); - return -1; + r = SSH_ERR_INVALID_FORMAT; + goto out; } + if (datalen >= SIZE_MAX - len) + return SSH_ERR_INVALID_ARGUMENT; smlen = len + datalen; - sm = xmalloc(smlen); + mlen = smlen; + if ((sm = malloc(smlen)) == NULL || (m = xmalloc(mlen)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } memcpy(sm, sigblob, len); memcpy(sm+len, data, datalen); - mlen = smlen; - m = xmalloc(mlen); if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, key->ed25519_pk)) != 0) { debug2("%s: crypto_sign_ed25519_open failed: %d", __func__, ret); } - if (ret == 0 && mlen != datalen) { - debug2("%s: crypto_sign_ed25519_open " - "mlen != datalen (%llu != %u)", __func__, mlen, datalen); - ret = -1; + if (ret != 0 || mlen != datalen) { + r = SSH_ERR_SIGNATURE_INVALID; + goto out; } /* XXX compare 'm' and 'data' ? */ - - explicit_bzero(sigblob, len); - explicit_bzero(sm, smlen); - explicit_bzero(m, smlen); /* NB. mlen may be invalid if ret != 0 */ - free(sigblob); - free(sm); - free(m); - debug("%s: signature %scorrect", __func__, (ret != 0) ? "in" : ""); - - /* translate return code carefully */ - return (ret == 0) ? 1 : -1; + /* success */ + r = 0; + out: + if (sm != NULL) { + explicit_bzero(sm, smlen); + free(sm); + } + if (m != NULL) { + explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */ + free(m); + } + sshbuf_free(b); + free(ktype); + return r; } +