GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/lib/../kexc25519c.c Lines: 63 70 90.0 %
Date: 2017-11-07 Branches: 21 42 50.0 %

Line Branch Exec Source
1
/* $OpenBSD: kexc25519c.c,v 1.8 2017/05/31 04:17:12 djm Exp $ */
2
/*
3
 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
4
 * Copyright (c) 2010 Damien Miller.  All rights reserved.
5
 * Copyright (c) 2013 Aris Adamantiadis.  All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
#include <sys/types.h>
29
30
#include <stdio.h>
31
#include <string.h>
32
#include <signal.h>
33
34
#include "sshkey.h"
35
#include "cipher.h"
36
#include "kex.h"
37
#include "log.h"
38
#include "packet.h"
39
#include "ssh2.h"
40
#include "sshbuf.h"
41
#include "digest.h"
42
#include "ssherr.h"
43
44
static int
45
input_kex_c25519_reply(int type, u_int32_t seq, struct ssh *ssh);
46
47
int
48
kexc25519_client(struct ssh *ssh)
49
{
50
2
	struct kex *kex = ssh->kex;
51
	int r;
52
53
1
	kexc25519_keygen(kex->c25519_client_key, kex->c25519_client_pubkey);
54
#ifdef DEBUG_KEXECDH
55
	dump_digest("client private key:", kex->c25519_client_key,
56
	    sizeof(kex->c25519_client_key));
57
#endif
58

2
	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
59
1
	    (r = sshpkt_put_string(ssh, kex->c25519_client_pubkey,
60
1
	    sizeof(kex->c25519_client_pubkey))) != 0 ||
61
1
	    (r = sshpkt_send(ssh)) != 0)
62
		return r;
63
64
1
	debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
65
1
	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_c25519_reply);
66
1
	return 0;
67
1
}
68
69
static int
70
input_kex_c25519_reply(int type, u_int32_t seq, struct ssh *ssh)
71
{
72
2
	struct kex *kex = ssh->kex;
73
1
	struct sshkey *server_host_key = NULL;
74
	struct sshbuf *shared_secret = NULL;
75
1
	u_char *server_pubkey = NULL;
76
1
	u_char *server_host_key_blob = NULL, *signature = NULL;
77
1
	u_char hash[SSH_DIGEST_MAX_LENGTH];
78
1
	size_t slen, pklen, sbloblen, hashlen;
79
	int r;
80
81
1
	if (kex->verify_host_key == NULL) {
82
		r = SSH_ERR_INVALID_ARGUMENT;
83
		goto out;
84
	}
85
86
	/* hostkey */
87
2
	if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
88
1
	    &sbloblen)) != 0 ||
89
1
	    (r = sshkey_from_blob(server_host_key_blob, sbloblen,
90
1
	    &server_host_key)) != 0)
91
		goto out;
92

2
	if (server_host_key->type != kex->hostkey_type ||
93
1
	    (kex->hostkey_type == KEY_ECDSA &&
94
1
	    server_host_key->ecdsa_nid != kex->hostkey_nid)) {
95
		r = SSH_ERR_KEY_TYPE_MISMATCH;
96
		goto out;
97
	}
98
1
	if (kex->verify_host_key(server_host_key, ssh) == -1) {
99
		r = SSH_ERR_SIGNATURE_INVALID;
100
		goto out;
101
	}
102
103
	/* Q_S, server public key */
104
	/* signed H */
105

2
	if ((r = sshpkt_get_string(ssh, &server_pubkey, &pklen)) != 0 ||
106
1
	    (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
107
1
	    (r = sshpkt_get_end(ssh)) != 0)
108
		goto out;
109
1
	if (pklen != CURVE25519_SIZE) {
110
		r = SSH_ERR_SIGNATURE_INVALID;
111
		goto out;
112
	}
113
114
#ifdef DEBUG_KEXECDH
115
	dump_digest("server public key:", server_pubkey, CURVE25519_SIZE);
116
#endif
117
118
1
	if ((shared_secret = sshbuf_new()) == NULL) {
119
		r = SSH_ERR_ALLOC_FAIL;
120
		goto out;
121
	}
122
2
	if ((r = kexc25519_shared_key(kex->c25519_client_key, server_pubkey,
123
1
	    shared_secret)) < 0)
124
		goto out;
125
126
	/* calc and verify H */
127
1
	hashlen = sizeof(hash);
128
2
	if ((r = kex_c25519_hash(
129
1
	    kex->hash_alg,
130
1
	    kex->client_version_string,
131
1
	    kex->server_version_string,
132
1
	    sshbuf_ptr(kex->my), sshbuf_len(kex->my),
133
1
	    sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
134
1
	    server_host_key_blob, sbloblen,
135
1
	    kex->c25519_client_pubkey,
136
1
	    server_pubkey,
137
1
	    sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
138
2
	    hash, &hashlen)) < 0)
139
		goto out;
140
141
3
	if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
142
2
	    ssh->compat)) != 0)
143
		goto out;
144
145
	/* save session id */
146
1
	if (kex->session_id == NULL) {
147
1
		kex->session_id_len = hashlen;
148
1
		kex->session_id = malloc(kex->session_id_len);
149
1
		if (kex->session_id == NULL) {
150
			r = SSH_ERR_ALLOC_FAIL;
151
			goto out;
152
		}
153
1
		memcpy(kex->session_id, hash, kex->session_id_len);
154
1
	}
155
156
1
	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
157
1
		r = kex_send_newkeys(ssh);
158
out:
159
1
	explicit_bzero(hash, sizeof(hash));
160
1
	explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
161
1
	free(server_host_key_blob);
162
1
	free(server_pubkey);
163
1
	free(signature);
164
1
	sshkey_free(server_host_key);
165
1
	sshbuf_free(shared_secret);
166
1
	return r;
167
1
}