1 /* $OpenBSD: ssh-ed25519.c,v 1.3 2014/02/23 20:03:42 djm Exp $ */ 2 /* 3 * Copyright (c) 2013 Markus Friedl <markus@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 20 #include "crypto_api.h" 21 22 #include <limits.h> 23 #include <string.h> 24 #include <stdarg.h> 25 26 #include "xmalloc.h" 27 #include "log.h" 28 #include "buffer.h" 29 #include "key.h" 30 #include "ssh.h" 31 32 int 33 ssh_ed25519_sign(const Key *key, u_char **sigp, u_int *lenp, 34 const u_char *data, u_int datalen) 35 { 36 u_char *sig; 37 u_int slen, len; 38 unsigned long long smlen; 39 int ret; 40 Buffer b; 41 42 if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || 43 key->ed25519_sk == NULL) { 44 error("%s: no ED25519 key", __func__); 45 return -1; 46 } 47 48 if (datalen >= UINT_MAX - crypto_sign_ed25519_BYTES) { 49 error("%s: datalen %u too long", __func__, datalen); 50 return -1; 51 } 52 smlen = slen = datalen + crypto_sign_ed25519_BYTES; 53 sig = xmalloc(slen); 54 55 if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, 56 key->ed25519_sk)) != 0 || smlen <= datalen) { 57 error("%s: crypto_sign_ed25519 failed: %d", __func__, ret); 58 free(sig); 59 return -1; 60 } 61 /* encode signature */ 62 buffer_init(&b); 63 buffer_put_cstring(&b, "ssh-ed25519"); 64 buffer_put_string(&b, sig, smlen - datalen); 65 len = buffer_len(&b); 66 if (lenp != NULL) 67 *lenp = len; 68 if (sigp != NULL) { 69 *sigp = xmalloc(len); 70 memcpy(*sigp, buffer_ptr(&b), len); 71 } 72 buffer_free(&b); 73 explicit_bzero(sig, slen); 74 free(sig); 75 76 return 0; 77 } 78 79 int 80 ssh_ed25519_verify(const Key *key, const u_char *signature, u_int signaturelen, 81 const u_char *data, u_int datalen) 82 { 83 Buffer b; 84 char *ktype; 85 u_char *sigblob, *sm, *m; 86 u_int len; 87 unsigned long long smlen, mlen; 88 int rlen, ret; 89 90 if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || 91 key->ed25519_pk == NULL) { 92 error("%s: no ED25519 key", __func__); 93 return -1; 94 } 95 buffer_init(&b); 96 buffer_append(&b, signature, signaturelen); 97 ktype = buffer_get_cstring(&b, NULL); 98 if (strcmp("ssh-ed25519", ktype) != 0) { 99 error("%s: cannot handle type %s", __func__, ktype); 100 buffer_free(&b); 101 free(ktype); 102 return -1; 103 } 104 free(ktype); 105 sigblob = buffer_get_string(&b, &len); 106 rlen = buffer_len(&b); 107 buffer_free(&b); 108 if (rlen != 0) { 109 error("%s: remaining bytes in signature %d", __func__, rlen); 110 free(sigblob); 111 return -1; 112 } 113 if (len > crypto_sign_ed25519_BYTES) { 114 error("%s: len %u > crypto_sign_ed25519_BYTES %u", __func__, 115 len, crypto_sign_ed25519_BYTES); 116 free(sigblob); 117 return -1; 118 } 119 smlen = len + datalen; 120 sm = xmalloc(smlen); 121 memcpy(sm, sigblob, len); 122 memcpy(sm+len, data, datalen); 123 mlen = smlen; 124 m = xmalloc(mlen); 125 if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, 126 key->ed25519_pk)) != 0) { 127 debug2("%s: crypto_sign_ed25519_open failed: %d", 128 __func__, ret); 129 } 130 if (ret == 0 && mlen != datalen) { 131 debug2("%s: crypto_sign_ed25519_open " 132 "mlen != datalen (%llu != %u)", __func__, mlen, datalen); 133 ret = -1; 134 } 135 /* XXX compare 'm' and 'data' ? */ 136 137 explicit_bzero(sigblob, len); 138 explicit_bzero(sm, smlen); 139 explicit_bzero(m, smlen); /* NB. mlen may be invalid if ret != 0 */ 140 free(sigblob); 141 free(sm); 142 free(m); 143 debug("%s: signature %scorrect", __func__, (ret != 0) ? "in" : ""); 144 145 /* translate return code carefully */ 146 return (ret == 0) ? 1 : -1; 147 } 148