Annotation of src/usr.bin/ssh/ssh-ecdsa.c, Revision 1.16
1.16 ! djm 1: /* $OpenBSD: ssh-ecdsa.c,v 1.15 2018/09/13 02:08:33 djm Exp $ */
1.1 djm 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:
1.11 djm 36: #include "sshbuf.h"
37: #include "ssherr.h"
1.8 djm 38: #include "digest.h"
1.11 djm 39: #define SSHKEY_INTERNAL
40: #include "sshkey.h"
1.1 djm 41:
1.11 djm 42: /* ARGSUSED */
1.1 djm 43: int
1.11 djm 44: ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
45: const u_char *data, size_t datalen, u_int compat)
1.1 djm 46: {
1.11 djm 47: ECDSA_SIG *sig = NULL;
1.15 djm 48: const BIGNUM *sig_r, *sig_s;
1.8 djm 49: int hash_alg;
50: u_char digest[SSH_DIGEST_MAX_LENGTH];
1.11 djm 51: size_t len, dlen;
52: struct sshbuf *b = NULL, *bb = NULL;
53: int ret = SSH_ERR_INTERNAL_ERROR;
1.1 djm 54:
1.11 djm 55: if (lenp != NULL)
56: *lenp = 0;
57: if (sigp != NULL)
58: *sigp = NULL;
59:
60: if (key == NULL || key->ecdsa == NULL ||
61: sshkey_type_plain(key->type) != KEY_ECDSA)
62: return SSH_ERR_INVALID_ARGUMENT;
63:
64: if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
65: (dlen = ssh_digest_bytes(hash_alg)) == 0)
66: return SSH_ERR_INTERNAL_ERROR;
67: if ((ret = ssh_digest_memory(hash_alg, data, datalen,
68: digest, sizeof(digest))) != 0)
69: goto out;
70:
71: if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) {
72: ret = SSH_ERR_LIBCRYPTO_ERROR;
73: goto out;
74: }
75:
76: if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
77: ret = SSH_ERR_ALLOC_FAIL;
78: goto out;
79: }
1.15 djm 80: ECDSA_SIG_get0(sig, &sig_r, &sig_s);
81: if ((ret = sshbuf_put_bignum2(bb, sig_r)) != 0 ||
82: (ret = sshbuf_put_bignum2(bb, sig_s)) != 0)
1.11 djm 83: goto out;
84: if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 ||
85: (ret = sshbuf_put_stringb(b, bb)) != 0)
86: goto out;
87: len = sshbuf_len(b);
88: if (sigp != NULL) {
89: if ((*sigp = malloc(len)) == NULL) {
90: ret = SSH_ERR_ALLOC_FAIL;
91: goto out;
92: }
93: memcpy(*sigp, sshbuf_ptr(b), len);
1.1 djm 94: }
95: if (lenp != NULL)
96: *lenp = len;
1.11 djm 97: ret = 0;
98: out:
99: explicit_bzero(digest, sizeof(digest));
1.12 mmcc 100: sshbuf_free(b);
101: sshbuf_free(bb);
1.14 jsing 102: ECDSA_SIG_free(sig);
1.11 djm 103: return ret;
104: }
1.1 djm 105:
1.11 djm 106: /* ARGSUSED */
1.1 djm 107: int
1.11 djm 108: ssh_ecdsa_verify(const struct sshkey *key,
109: const u_char *signature, size_t signaturelen,
110: const u_char *data, size_t datalen, u_int compat)
1.1 djm 111: {
1.11 djm 112: ECDSA_SIG *sig = NULL;
1.15 djm 113: BIGNUM *sig_r = NULL, *sig_s = NULL;
1.8 djm 114: int hash_alg;
1.11 djm 115: u_char digest[SSH_DIGEST_MAX_LENGTH];
116: size_t dlen;
117: int ret = SSH_ERR_INTERNAL_ERROR;
118: struct sshbuf *b = NULL, *sigbuf = NULL;
119: char *ktype = NULL;
120:
121: if (key == NULL || key->ecdsa == NULL ||
1.13 djm 122: sshkey_type_plain(key->type) != KEY_ECDSA ||
123: signature == NULL || signaturelen == 0)
1.11 djm 124: return SSH_ERR_INVALID_ARGUMENT;
125:
126: if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
127: (dlen = ssh_digest_bytes(hash_alg)) == 0)
128: return SSH_ERR_INTERNAL_ERROR;
1.7 djm 129:
1.1 djm 130: /* fetch signature */
1.11 djm 131: if ((b = sshbuf_from(signature, signaturelen)) == NULL)
132: return SSH_ERR_ALLOC_FAIL;
133: if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
134: sshbuf_froms(b, &sigbuf) != 0) {
135: ret = SSH_ERR_INVALID_FORMAT;
136: goto out;
137: }
138: if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
139: ret = SSH_ERR_KEY_TYPE_MISMATCH;
140: goto out;
141: }
142: if (sshbuf_len(b) != 0) {
143: ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
144: goto out;
1.1 djm 145: }
146:
147: /* parse signature */
1.16 ! djm 148: if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 ||
! 149: sshbuf_get_bignum2(sigbuf, &sig_s) != 0) {
! 150: ret = SSH_ERR_INVALID_FORMAT;
1.11 djm 151: goto out;
152: }
1.16 ! djm 153: if ((sig = ECDSA_SIG_new()) == NULL) {
! 154: ret = SSH_ERR_ALLOC_FAIL;
1.11 djm 155: goto out;
156: }
1.15 djm 157: if (!ECDSA_SIG_set0(sig, sig_r, sig_s)) {
158: ret = SSH_ERR_LIBCRYPTO_ERROR;
159: goto out;
160: }
161: sig_r = sig_s = NULL; /* transferred */
162:
1.11 djm 163: if (sshbuf_len(sigbuf) != 0) {
164: ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
165: goto out;
166: }
167: if ((ret = ssh_digest_memory(hash_alg, data, datalen,
168: digest, sizeof(digest))) != 0)
169: goto out;
170:
171: switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) {
172: case 1:
173: ret = 0;
174: break;
175: case 0:
176: ret = SSH_ERR_SIGNATURE_INVALID;
177: goto out;
178: default:
179: ret = SSH_ERR_LIBCRYPTO_ERROR;
180: goto out;
1.8 djm 181: }
1.1 djm 182:
1.11 djm 183: out:
1.9 djm 184: explicit_bzero(digest, sizeof(digest));
1.12 mmcc 185: sshbuf_free(sigbuf);
186: sshbuf_free(b);
1.14 jsing 187: ECDSA_SIG_free(sig);
1.15 djm 188: BN_clear_free(sig_r);
189: BN_clear_free(sig_s);
1.11 djm 190: free(ktype);
1.1 djm 191: return ret;
192: }