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