ssh-ecdsa.c revision 255767
1255767Sdes/* $OpenBSD: ssh-ecdsa.c,v 1.6 2013/05/17 00:13:14 djm Exp $ */
2218767Sdes/*
3218767Sdes * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4218767Sdes * Copyright (c) 2010 Damien Miller.  All rights reserved.
5218767Sdes *
6218767Sdes * Redistribution and use in source and binary forms, with or without
7218767Sdes * modification, are permitted provided that the following conditions
8218767Sdes * are met:
9218767Sdes * 1. Redistributions of source code must retain the above copyright
10218767Sdes *    notice, this list of conditions and the following disclaimer.
11218767Sdes * 2. Redistributions in binary form must reproduce the above copyright
12218767Sdes *    notice, this list of conditions and the following disclaimer in the
13218767Sdes *    documentation and/or other materials provided with the distribution.
14218767Sdes *
15218767Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16218767Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17218767Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18218767Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19218767Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20218767Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21218767Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22218767Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23218767Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24218767Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25218767Sdes */
26218767Sdes
27218767Sdes#include "includes.h"
28218767Sdes
29218767Sdes#ifdef OPENSSL_HAS_ECC
30218767Sdes
31218767Sdes#include <sys/types.h>
32218767Sdes
33218767Sdes#include <openssl/bn.h>
34218767Sdes#include <openssl/ec.h>
35218767Sdes#include <openssl/ecdsa.h>
36218767Sdes#include <openssl/evp.h>
37218767Sdes
38218767Sdes#include <string.h>
39218767Sdes
40218767Sdes#include "xmalloc.h"
41218767Sdes#include "buffer.h"
42218767Sdes#include "compat.h"
43218767Sdes#include "log.h"
44218767Sdes#include "key.h"
45218767Sdes
46218767Sdesint
47218767Sdesssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp,
48218767Sdes    const u_char *data, u_int datalen)
49218767Sdes{
50218767Sdes	ECDSA_SIG *sig;
51218767Sdes	const EVP_MD *evp_md;
52218767Sdes	EVP_MD_CTX md;
53218767Sdes	u_char digest[EVP_MAX_MD_SIZE];
54218767Sdes	u_int len, dlen;
55218767Sdes	Buffer b, bb;
56218767Sdes
57218767Sdes	if (key == NULL || key->ecdsa == NULL ||
58218767Sdes	    (key->type != KEY_ECDSA && key->type != KEY_ECDSA_CERT)) {
59218767Sdes		error("%s: no ECDSA key", __func__);
60218767Sdes		return -1;
61218767Sdes	}
62218767Sdes	evp_md = key_ec_nid_to_evpmd(key->ecdsa_nid);
63218767Sdes	EVP_DigestInit(&md, evp_md);
64218767Sdes	EVP_DigestUpdate(&md, data, datalen);
65218767Sdes	EVP_DigestFinal(&md, digest, &dlen);
66218767Sdes
67218767Sdes	sig = ECDSA_do_sign(digest, dlen, key->ecdsa);
68218767Sdes	memset(digest, 'd', sizeof(digest));
69218767Sdes
70218767Sdes	if (sig == NULL) {
71218767Sdes		error("%s: sign failed", __func__);
72218767Sdes		return -1;
73218767Sdes	}
74218767Sdes
75218767Sdes	buffer_init(&bb);
76218767Sdes	buffer_put_bignum2(&bb, sig->r);
77218767Sdes	buffer_put_bignum2(&bb, sig->s);
78218767Sdes	ECDSA_SIG_free(sig);
79218767Sdes
80218767Sdes	buffer_init(&b);
81218767Sdes	buffer_put_cstring(&b, key_ssh_name_plain(key));
82218767Sdes	buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb));
83218767Sdes	buffer_free(&bb);
84218767Sdes	len = buffer_len(&b);
85218767Sdes	if (lenp != NULL)
86218767Sdes		*lenp = len;
87218767Sdes	if (sigp != NULL) {
88218767Sdes		*sigp = xmalloc(len);
89218767Sdes		memcpy(*sigp, buffer_ptr(&b), len);
90218767Sdes	}
91218767Sdes	buffer_free(&b);
92218767Sdes
93218767Sdes	return 0;
94218767Sdes}
95218767Sdesint
96218767Sdesssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
97218767Sdes    const u_char *data, u_int datalen)
98218767Sdes{
99218767Sdes	ECDSA_SIG *sig;
100218767Sdes	const EVP_MD *evp_md;
101218767Sdes	EVP_MD_CTX md;
102218767Sdes	u_char digest[EVP_MAX_MD_SIZE], *sigblob;
103218767Sdes	u_int len, dlen;
104218767Sdes	int rlen, ret;
105218767Sdes	Buffer b, bb;
106218767Sdes	char *ktype;
107218767Sdes
108218767Sdes	if (key == NULL || key->ecdsa == NULL ||
109218767Sdes	    (key->type != KEY_ECDSA && key->type != KEY_ECDSA_CERT)) {
110218767Sdes		error("%s: no ECDSA key", __func__);
111218767Sdes		return -1;
112218767Sdes	}
113218767Sdes	evp_md = key_ec_nid_to_evpmd(key->ecdsa_nid);
114218767Sdes
115218767Sdes	/* fetch signature */
116218767Sdes	buffer_init(&b);
117218767Sdes	buffer_append(&b, signature, signaturelen);
118218767Sdes	ktype = buffer_get_string(&b, NULL);
119218767Sdes	if (strcmp(key_ssh_name_plain(key), ktype) != 0) {
120218767Sdes		error("%s: cannot handle type %s", __func__, ktype);
121218767Sdes		buffer_free(&b);
122255767Sdes		free(ktype);
123218767Sdes		return -1;
124218767Sdes	}
125255767Sdes	free(ktype);
126218767Sdes	sigblob = buffer_get_string(&b, &len);
127218767Sdes	rlen = buffer_len(&b);
128218767Sdes	buffer_free(&b);
129218767Sdes	if (rlen != 0) {
130218767Sdes		error("%s: remaining bytes in signature %d", __func__, rlen);
131255767Sdes		free(sigblob);
132218767Sdes		return -1;
133218767Sdes	}
134218767Sdes
135218767Sdes	/* parse signature */
136218767Sdes	if ((sig = ECDSA_SIG_new()) == NULL)
137218767Sdes		fatal("%s: ECDSA_SIG_new failed", __func__);
138218767Sdes	if ((sig->r = BN_new()) == NULL ||
139218767Sdes	    (sig->s = BN_new()) == NULL)
140218767Sdes		fatal("%s: BN_new failed", __func__);
141218767Sdes
142218767Sdes	buffer_init(&bb);
143218767Sdes	buffer_append(&bb, sigblob, len);
144218767Sdes	buffer_get_bignum2(&bb, sig->r);
145218767Sdes	buffer_get_bignum2(&bb, sig->s);
146218767Sdes	if (buffer_len(&bb) != 0)
147218767Sdes		fatal("%s: remaining bytes in inner sigblob", __func__);
148240075Sdes	buffer_free(&bb);
149218767Sdes
150218767Sdes	/* clean up */
151218767Sdes	memset(sigblob, 0, len);
152255767Sdes	free(sigblob);
153218767Sdes
154218767Sdes	/* hash the data */
155218767Sdes	EVP_DigestInit(&md, evp_md);
156218767Sdes	EVP_DigestUpdate(&md, data, datalen);
157218767Sdes	EVP_DigestFinal(&md, digest, &dlen);
158218767Sdes
159218767Sdes	ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa);
160218767Sdes	memset(digest, 'd', sizeof(digest));
161218767Sdes
162218767Sdes	ECDSA_SIG_free(sig);
163218767Sdes
164218767Sdes	debug("%s: signature %s", __func__,
165218767Sdes	    ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
166218767Sdes	return ret;
167218767Sdes}
168218767Sdes
169218767Sdes#endif /* OPENSSL_HAS_ECC */
170