1 /* $OpenBSD: ssh-ecdsa.c,v 1.10 2014/02/03 23:28:00 djm Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2010 Damien Miller. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/types.h> 28 29 #include <openssl/bn.h> 30 #include <openssl/ec.h> 31 #include <openssl/ecdsa.h> 32 #include <openssl/evp.h> 33 34 #include <string.h> 35 36 #include "xmalloc.h" 37 #include "buffer.h" 38 #include "compat.h" 39 #include "log.h" 40 #include "key.h" 41 #include "digest.h" 42 43 int 44 ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp, 45 const u_char *data, u_int datalen) 46 { 47 ECDSA_SIG *sig; 48 int hash_alg; 49 u_char digest[SSH_DIGEST_MAX_LENGTH]; 50 u_int len, dlen; 51 Buffer b, bb; 52 53 if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || 54 key->ecdsa == NULL) { 55 error("%s: no ECDSA key", __func__); 56 return -1; 57 } 58 59 hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); 60 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 61 error("%s: bad hash algorithm %d", __func__, hash_alg); 62 return -1; 63 } 64 if (ssh_digest_memory(hash_alg, data, datalen, 65 digest, sizeof(digest)) != 0) { 66 error("%s: digest_memory failed", __func__); 67 return -1; 68 } 69 70 sig = ECDSA_do_sign(digest, dlen, key->ecdsa); 71 explicit_bzero(digest, sizeof(digest)); 72 73 if (sig == NULL) { 74 error("%s: sign failed", __func__); 75 return -1; 76 } 77 78 buffer_init(&bb); 79 buffer_put_bignum2(&bb, sig->r); 80 buffer_put_bignum2(&bb, sig->s); 81 ECDSA_SIG_free(sig); 82 83 buffer_init(&b); 84 buffer_put_cstring(&b, key_ssh_name_plain(key)); 85 buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb)); 86 buffer_free(&bb); 87 len = buffer_len(&b); 88 if (lenp != NULL) 89 *lenp = len; 90 if (sigp != NULL) { 91 *sigp = xmalloc(len); 92 memcpy(*sigp, buffer_ptr(&b), len); 93 } 94 buffer_free(&b); 95 96 return 0; 97 } 98 int 99 ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 100 const u_char *data, u_int datalen) 101 { 102 ECDSA_SIG *sig; 103 int hash_alg; 104 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 105 u_int len, dlen; 106 int rlen, ret; 107 Buffer b, bb; 108 char *ktype; 109 110 if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || 111 key->ecdsa == NULL) { 112 error("%s: no ECDSA key", __func__); 113 return -1; 114 } 115 116 /* fetch signature */ 117 buffer_init(&b); 118 buffer_append(&b, signature, signaturelen); 119 ktype = buffer_get_string(&b, NULL); 120 if (strcmp(key_ssh_name_plain(key), ktype) != 0) { 121 error("%s: cannot handle type %s", __func__, ktype); 122 buffer_free(&b); 123 free(ktype); 124 return -1; 125 } 126 free(ktype); 127 sigblob = buffer_get_string(&b, &len); 128 rlen = buffer_len(&b); 129 buffer_free(&b); 130 if (rlen != 0) { 131 error("%s: remaining bytes in signature %d", __func__, rlen); 132 free(sigblob); 133 return -1; 134 } 135 136 /* parse signature */ 137 if ((sig = ECDSA_SIG_new()) == NULL) 138 fatal("%s: ECDSA_SIG_new failed", __func__); 139 140 buffer_init(&bb); 141 buffer_append(&bb, sigblob, len); 142 buffer_get_bignum2(&bb, sig->r); 143 buffer_get_bignum2(&bb, sig->s); 144 if (buffer_len(&bb) != 0) 145 fatal("%s: remaining bytes in inner sigblob", __func__); 146 buffer_free(&bb); 147 148 /* clean up */ 149 explicit_bzero(sigblob, len); 150 free(sigblob); 151 152 /* hash the data */ 153 hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); 154 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 155 error("%s: bad hash algorithm %d", __func__, hash_alg); 156 return -1; 157 } 158 if (ssh_digest_memory(hash_alg, data, datalen, 159 digest, sizeof(digest)) != 0) { 160 error("%s: digest_memory failed", __func__); 161 return -1; 162 } 163 164 ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa); 165 explicit_bzero(digest, sizeof(digest)); 166 167 ECDSA_SIG_free(sig); 168 169 debug("%s: signature %s", __func__, 170 ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 171 return ret; 172 } 173