xref: /freebsd/crypto/openssh/ssh-ecdsa.c (revision 5b9c547c)
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 "includes.h"
28 
29 #ifdef OPENSSL_HAS_ECC
30 
31 #include <sys/types.h>
32 
33 #include <openssl/bn.h>
34 #include <openssl/ec.h>
35 #include <openssl/ecdsa.h>
36 #include <openssl/evp.h>
37 
38 #include <string.h>
39 
40 #include "xmalloc.h"
41 #include "buffer.h"
42 #include "compat.h"
43 #include "log.h"
44 #include "key.h"
45 #include "digest.h"
46 
47 int
48 ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp,
49     const u_char *data, u_int datalen)
50 {
51 	ECDSA_SIG *sig;
52 	int hash_alg;
53 	u_char digest[SSH_DIGEST_MAX_LENGTH];
54 	u_int len, dlen;
55 	Buffer b, bb;
56 
57 	if (key == NULL || key_type_plain(key->type) != KEY_ECDSA ||
58 	    key->ecdsa == NULL) {
59 		error("%s: no ECDSA key", __func__);
60 		return -1;
61 	}
62 
63 	hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid);
64 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
65 		error("%s: bad hash algorithm %d", __func__, hash_alg);
66 		return -1;
67 	}
68 	if (ssh_digest_memory(hash_alg, data, datalen,
69 	    digest, sizeof(digest)) != 0) {
70 		error("%s: digest_memory failed", __func__);
71 		return -1;
72 	}
73 
74 	sig = ECDSA_do_sign(digest, dlen, key->ecdsa);
75 	explicit_bzero(digest, sizeof(digest));
76 
77 	if (sig == NULL) {
78 		error("%s: sign failed", __func__);
79 		return -1;
80 	}
81 
82 	buffer_init(&bb);
83 	buffer_put_bignum2(&bb, sig->r);
84 	buffer_put_bignum2(&bb, sig->s);
85 	ECDSA_SIG_free(sig);
86 
87 	buffer_init(&b);
88 	buffer_put_cstring(&b, key_ssh_name_plain(key));
89 	buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb));
90 	buffer_free(&bb);
91 	len = buffer_len(&b);
92 	if (lenp != NULL)
93 		*lenp = len;
94 	if (sigp != NULL) {
95 		*sigp = xmalloc(len);
96 		memcpy(*sigp, buffer_ptr(&b), len);
97 	}
98 	buffer_free(&b);
99 
100 	return 0;
101 }
102 int
103 ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
104     const u_char *data, u_int datalen)
105 {
106 	ECDSA_SIG *sig;
107 	int hash_alg;
108 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob;
109 	u_int len, dlen;
110 	int rlen, ret;
111 	Buffer b, bb;
112 	char *ktype;
113 
114 	if (key == NULL || key_type_plain(key->type) != KEY_ECDSA ||
115 	    key->ecdsa == NULL) {
116 		error("%s: no ECDSA key", __func__);
117 		return -1;
118 	}
119 
120 	/* fetch signature */
121 	buffer_init(&b);
122 	buffer_append(&b, signature, signaturelen);
123 	ktype = buffer_get_string(&b, NULL);
124 	if (strcmp(key_ssh_name_plain(key), ktype) != 0) {
125 		error("%s: cannot handle type %s", __func__, ktype);
126 		buffer_free(&b);
127 		free(ktype);
128 		return -1;
129 	}
130 	free(ktype);
131 	sigblob = buffer_get_string(&b, &len);
132 	rlen = buffer_len(&b);
133 	buffer_free(&b);
134 	if (rlen != 0) {
135 		error("%s: remaining bytes in signature %d", __func__, rlen);
136 		free(sigblob);
137 		return -1;
138 	}
139 
140 	/* parse signature */
141 	if ((sig = ECDSA_SIG_new()) == NULL)
142 		fatal("%s: ECDSA_SIG_new failed", __func__);
143 
144 	buffer_init(&bb);
145 	buffer_append(&bb, sigblob, len);
146 	buffer_get_bignum2(&bb, sig->r);
147 	buffer_get_bignum2(&bb, sig->s);
148 	if (buffer_len(&bb) != 0)
149 		fatal("%s: remaining bytes in inner sigblob", __func__);
150 	buffer_free(&bb);
151 
152 	/* clean up */
153 	explicit_bzero(sigblob, len);
154 	free(sigblob);
155 
156 	/* hash the data */
157 	hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid);
158 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
159 		error("%s: bad hash algorithm %d", __func__, hash_alg);
160 		return -1;
161 	}
162 	if (ssh_digest_memory(hash_alg, data, datalen,
163 	    digest, sizeof(digest)) != 0) {
164 		error("%s: digest_memory failed", __func__);
165 		return -1;
166 	}
167 
168 	ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa);
169 	explicit_bzero(digest, sizeof(digest));
170 
171 	ECDSA_SIG_free(sig);
172 
173 	debug("%s: signature %s", __func__,
174 	    ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
175 	return ret;
176 }
177 
178 #endif /* OPENSSL_HAS_ECC */
179