1 /* $NetBSD: ssh-ecdsa.c,v 1.12 2018/04/06 18:59:00 christos Exp $ */ 2 /* $OpenBSD: ssh-ecdsa.c,v 1.14 2018/02/07 02:06:51 jsing Exp $ */ 3 /* 4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 5 * Copyright (c) 2010 Damien Miller. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "includes.h" 29 __RCSID("$NetBSD: ssh-ecdsa.c,v 1.12 2018/04/06 18:59:00 christos Exp $"); 30 #include <sys/types.h> 31 32 #include <openssl/bn.h> 33 #include <openssl/ec.h> 34 #include <openssl/ecdsa.h> 35 #include <openssl/evp.h> 36 37 #include <string.h> 38 39 #include "sshbuf.h" 40 #include "ssherr.h" 41 #include "digest.h" 42 #define SSHKEY_INTERNAL 43 #include "sshkey.h" 44 45 /* ARGSUSED */ 46 int 47 ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 48 const u_char *data, size_t datalen, u_int compat) 49 { 50 ECDSA_SIG *sig = NULL; 51 int hash_alg; 52 u_char digest[SSH_DIGEST_MAX_LENGTH]; 53 size_t len, dlen; 54 struct sshbuf *b = NULL, *bb = NULL; 55 int ret = SSH_ERR_INTERNAL_ERROR; 56 57 if (lenp != NULL) 58 *lenp = 0; 59 if (sigp != NULL) 60 *sigp = NULL; 61 62 if (key == NULL || key->ecdsa == NULL || 63 sshkey_type_plain(key->type) != KEY_ECDSA) 64 return SSH_ERR_INVALID_ARGUMENT; 65 66 if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || 67 (dlen = ssh_digest_bytes(hash_alg)) == 0) 68 return SSH_ERR_INTERNAL_ERROR; 69 if ((ret = ssh_digest_memory(hash_alg, data, datalen, 70 digest, sizeof(digest))) != 0) 71 goto out; 72 73 if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) { 74 ret = SSH_ERR_LIBCRYPTO_ERROR; 75 goto out; 76 } 77 78 if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { 79 ret = SSH_ERR_ALLOC_FAIL; 80 goto out; 81 } 82 { 83 const BIGNUM *r, *s; 84 ECDSA_SIG_get0(sig, &r, &s); 85 if ((ret = sshbuf_put_bignum2(bb, r)) != 0 || 86 (ret = sshbuf_put_bignum2(bb, s)) != 0) { 87 goto out; 88 } 89 } 90 if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 || 91 (ret = sshbuf_put_stringb(b, bb)) != 0) 92 goto out; 93 len = sshbuf_len(b); 94 if (sigp != NULL) { 95 if ((*sigp = malloc(len)) == NULL) { 96 ret = SSH_ERR_ALLOC_FAIL; 97 goto out; 98 } 99 memcpy(*sigp, sshbuf_ptr(b), len); 100 } 101 if (lenp != NULL) 102 *lenp = len; 103 ret = 0; 104 out: 105 explicit_bzero(digest, sizeof(digest)); 106 sshbuf_free(b); 107 sshbuf_free(bb); 108 ECDSA_SIG_free(sig); 109 return ret; 110 } 111 112 /* ARGSUSED */ 113 int 114 ssh_ecdsa_verify(const struct sshkey *key, 115 const u_char *signature, size_t signaturelen, 116 const u_char *data, size_t datalen, u_int compat) 117 { 118 ECDSA_SIG *sig = NULL; 119 int hash_alg; 120 u_char digest[SSH_DIGEST_MAX_LENGTH]; 121 size_t dlen; 122 int ret = SSH_ERR_INTERNAL_ERROR; 123 struct sshbuf *b = NULL, *sigbuf = NULL; 124 char *ktype = NULL; 125 126 if (key == NULL || key->ecdsa == NULL || 127 sshkey_type_plain(key->type) != KEY_ECDSA || 128 signature == NULL || signaturelen == 0) 129 return SSH_ERR_INVALID_ARGUMENT; 130 131 if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || 132 (dlen = ssh_digest_bytes(hash_alg)) == 0) 133 return SSH_ERR_INTERNAL_ERROR; 134 135 /* fetch signature */ 136 if ((b = sshbuf_from(signature, signaturelen)) == NULL) 137 return SSH_ERR_ALLOC_FAIL; 138 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 139 sshbuf_froms(b, &sigbuf) != 0) { 140 ret = SSH_ERR_INVALID_FORMAT; 141 goto out; 142 } 143 if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) { 144 ret = SSH_ERR_KEY_TYPE_MISMATCH; 145 goto out; 146 } 147 if (sshbuf_len(b) != 0) { 148 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 149 goto out; 150 } 151 152 /* parse signature */ 153 if ((sig = ECDSA_SIG_new()) == NULL) { 154 ret = SSH_ERR_ALLOC_FAIL; 155 goto out; 156 } 157 { 158 BIGNUM *r=NULL, *s=NULL; 159 if ((r = BN_new()) == NULL || 160 (s = BN_new()) == NULL) { 161 ret = SSH_ERR_ALLOC_FAIL; 162 goto out_rs; 163 } 164 if (sshbuf_get_bignum2(sigbuf, r) != 0 || 165 sshbuf_get_bignum2(sigbuf, s) != 0) { 166 ret = SSH_ERR_INVALID_FORMAT; 167 goto out_rs; 168 } 169 if (ECDSA_SIG_set0(sig, r, s) == 0) { 170 ret = SSH_ERR_LIBCRYPTO_ERROR; 171 out_rs: 172 BN_free(r); 173 BN_free(s); 174 goto out; 175 } 176 r = s = NULL; 177 } 178 if (sshbuf_len(sigbuf) != 0) { 179 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 180 goto out; 181 } 182 if ((ret = ssh_digest_memory(hash_alg, data, datalen, 183 digest, sizeof(digest))) != 0) 184 goto out; 185 186 switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) { 187 case 1: 188 ret = 0; 189 break; 190 case 0: 191 ret = SSH_ERR_SIGNATURE_INVALID; 192 goto out; 193 default: 194 ret = SSH_ERR_LIBCRYPTO_ERROR; 195 goto out; 196 } 197 198 out: 199 explicit_bzero(digest, sizeof(digest)); 200 sshbuf_free(sigbuf); 201 sshbuf_free(b); 202 ECDSA_SIG_free(sig); 203 free(ktype); 204 return ret; 205 } 206