1 /* $OpenBSD: kexc25519c.c,v 1.7 2015/01/26 06:10:03 djm Exp $ */
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.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
30 #include <sys/types.h>
47 input_kex_c25519_reply(int type
, u_int32_t seq
, void *ctxt
);
50 kexc25519_client(struct ssh
*ssh
)
52 struct kex
*kex
= ssh
->kex
;
55 kexc25519_keygen(kex
->c25519_client_key
, kex
->c25519_client_pubkey
);
57 dump_digest("client private key:", kex
->c25519_client_key
,
58 sizeof(kex
->c25519_client_key
));
60 if ((r
= sshpkt_start(ssh
, SSH2_MSG_KEX_ECDH_INIT
)) != 0 ||
61 (r
= sshpkt_put_string(ssh
, kex
->c25519_client_pubkey
,
62 sizeof(kex
->c25519_client_pubkey
))) != 0 ||
63 (r
= sshpkt_send(ssh
)) != 0)
66 debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
67 ssh_dispatch_set(ssh
, SSH2_MSG_KEX_ECDH_REPLY
, &input_kex_c25519_reply
);
72 input_kex_c25519_reply(int type
, u_int32_t seq
, void *ctxt
)
74 struct ssh
*ssh
= ctxt
;
75 struct kex
*kex
= ssh
->kex
;
76 struct sshkey
*server_host_key
= NULL
;
77 struct sshbuf
*shared_secret
= NULL
;
78 u_char
*server_pubkey
= NULL
;
79 u_char
*server_host_key_blob
= NULL
, *signature
= NULL
;
80 u_char hash
[SSH_DIGEST_MAX_LENGTH
];
81 size_t slen
, pklen
, sbloblen
, hashlen
;
84 if (kex
->verify_host_key
== NULL
) {
85 r
= SSH_ERR_INVALID_ARGUMENT
;
90 if ((r
= sshpkt_get_string(ssh
, &server_host_key_blob
,
92 (r
= sshkey_from_blob(server_host_key_blob
, sbloblen
,
93 &server_host_key
)) != 0)
95 if (server_host_key
->type
!= kex
->hostkey_type
||
96 (kex
->hostkey_type
== KEY_ECDSA
&&
97 server_host_key
->ecdsa_nid
!= kex
->hostkey_nid
)) {
98 r
= SSH_ERR_KEY_TYPE_MISMATCH
;
101 if (kex
->verify_host_key(server_host_key
, ssh
) == -1) {
102 r
= SSH_ERR_SIGNATURE_INVALID
;
106 /* Q_S, server public key */
108 if ((r
= sshpkt_get_string(ssh
, &server_pubkey
, &pklen
)) != 0 ||
109 (r
= sshpkt_get_string(ssh
, &signature
, &slen
)) != 0 ||
110 (r
= sshpkt_get_end(ssh
)) != 0)
112 if (pklen
!= CURVE25519_SIZE
) {
113 r
= SSH_ERR_SIGNATURE_INVALID
;
118 dump_digest("server public key:", server_pubkey
, CURVE25519_SIZE
);
121 if ((shared_secret
= sshbuf_new()) == NULL
) {
122 r
= SSH_ERR_ALLOC_FAIL
;
125 if ((r
= kexc25519_shared_key(kex
->c25519_client_key
, server_pubkey
,
129 /* calc and verify H */
130 hashlen
= sizeof(hash
);
131 if ((r
= kex_c25519_hash(
133 kex
->client_version_string
,
134 kex
->server_version_string
,
135 sshbuf_ptr(kex
->my
), sshbuf_len(kex
->my
),
136 sshbuf_ptr(kex
->peer
), sshbuf_len(kex
->peer
),
137 server_host_key_blob
, sbloblen
,
138 kex
->c25519_client_pubkey
,
140 sshbuf_ptr(shared_secret
), sshbuf_len(shared_secret
),
141 hash
, &hashlen
)) < 0)
144 if ((r
= sshkey_verify(server_host_key
, signature
, slen
, hash
, hashlen
,
148 /* save session id */
149 if (kex
->session_id
== NULL
) {
150 kex
->session_id_len
= hashlen
;
151 kex
->session_id
= malloc(kex
->session_id_len
);
152 if (kex
->session_id
== NULL
) {
153 r
= SSH_ERR_ALLOC_FAIL
;
156 memcpy(kex
->session_id
, hash
, kex
->session_id_len
);
159 if ((r
= kex_derive_keys(ssh
, hash
, hashlen
, shared_secret
)) == 0)
160 r
= kex_send_newkeys(ssh
);
162 explicit_bzero(hash
, sizeof(hash
));
163 explicit_bzero(kex
->c25519_client_key
, sizeof(kex
->c25519_client_key
));
164 free(server_host_key_blob
);
167 sshkey_free(server_host_key
);
168 sshbuf_free(shared_secret
);