/src/libssh/src/curve25519_crypto.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * curve25519_crypto.c - Curve25519 ECDH functions for key exchange (OpenSSL) |
3 | | * |
4 | | * This file is part of the SSH Library |
5 | | * |
6 | | * Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be> |
7 | | * |
8 | | * The SSH Library is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU Lesser General Public License as published by |
10 | | * the Free Software Foundation, version 2.1 of the License. |
11 | | * |
12 | | * The SSH Library is distributed in the hope that it will be useful, but |
13 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
14 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
15 | | * License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with the SSH Library; see the file COPYING. If not, write to |
19 | | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
20 | | * MA 02111-1307, USA. |
21 | | */ |
22 | | |
23 | | #include "config.h" |
24 | | #include "libssh/curve25519.h" |
25 | | |
26 | | #include "libssh/crypto.h" |
27 | | #include "libssh/priv.h" |
28 | | #include "libssh/session.h" |
29 | | |
30 | | #include <openssl/err.h> |
31 | | #include <openssl/evp.h> |
32 | | |
33 | | int ssh_curve25519_init(ssh_session session) |
34 | 0 | { |
35 | 0 | ssh_curve25519_pubkey *pubkey_loc = NULL; |
36 | 0 | EVP_PKEY_CTX *pctx = NULL; |
37 | 0 | EVP_PKEY *pkey = NULL; |
38 | 0 | size_t pubkey_len = CURVE25519_PUBKEY_SIZE; |
39 | 0 | int rc; |
40 | |
|
41 | 0 | if (session->server) { |
42 | 0 | pubkey_loc = &session->next_crypto->curve25519_server_pubkey; |
43 | 0 | } else { |
44 | 0 | pubkey_loc = &session->next_crypto->curve25519_client_pubkey; |
45 | 0 | } |
46 | |
|
47 | 0 | pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); |
48 | 0 | if (pctx == NULL) { |
49 | 0 | SSH_LOG(SSH_LOG_TRACE, |
50 | 0 | "Failed to initialize X25519 context: %s", |
51 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
52 | 0 | return SSH_ERROR; |
53 | 0 | } |
54 | | |
55 | 0 | rc = EVP_PKEY_keygen_init(pctx); |
56 | 0 | if (rc != 1) { |
57 | 0 | SSH_LOG(SSH_LOG_TRACE, |
58 | 0 | "Failed to initialize X25519 keygen: %s", |
59 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
60 | 0 | EVP_PKEY_CTX_free(pctx); |
61 | 0 | return SSH_ERROR; |
62 | 0 | } |
63 | | |
64 | 0 | rc = EVP_PKEY_keygen(pctx, &pkey); |
65 | 0 | EVP_PKEY_CTX_free(pctx); |
66 | 0 | if (rc != 1) { |
67 | 0 | SSH_LOG(SSH_LOG_TRACE, |
68 | 0 | "Failed to generate X25519 keys: %s", |
69 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
70 | 0 | return SSH_ERROR; |
71 | 0 | } |
72 | | |
73 | 0 | rc = EVP_PKEY_get_raw_public_key(pkey, *pubkey_loc, &pubkey_len); |
74 | 0 | if (rc != 1) { |
75 | 0 | SSH_LOG(SSH_LOG_TRACE, |
76 | 0 | "Failed to get X25519 raw public key: %s", |
77 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
78 | 0 | EVP_PKEY_free(pkey); |
79 | 0 | return SSH_ERROR; |
80 | 0 | } |
81 | | |
82 | 0 | session->next_crypto->curve25519_privkey = pkey; |
83 | 0 | pkey = NULL; |
84 | |
|
85 | 0 | return SSH_OK; |
86 | 0 | } |
87 | | |
88 | | int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k) |
89 | 0 | { |
90 | 0 | ssh_curve25519_pubkey *peer_pubkey_loc = NULL; |
91 | 0 | int rc, ret = SSH_ERROR; |
92 | 0 | EVP_PKEY_CTX *pctx = NULL; |
93 | 0 | EVP_PKEY *pkey = NULL, *pubkey = NULL; |
94 | 0 | size_t shared_key_len = CURVE25519_PUBKEY_SIZE; |
95 | |
|
96 | 0 | if (session->server) { |
97 | 0 | peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey; |
98 | 0 | } else { |
99 | 0 | peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey; |
100 | 0 | } |
101 | |
|
102 | 0 | pkey = session->next_crypto->curve25519_privkey; |
103 | 0 | if (pkey == NULL) { |
104 | 0 | SSH_LOG(SSH_LOG_TRACE, |
105 | 0 | "Failed to create X25519 EVP_PKEY: %s", |
106 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
107 | 0 | return SSH_ERROR; |
108 | 0 | } |
109 | | |
110 | 0 | pctx = EVP_PKEY_CTX_new(pkey, NULL); |
111 | 0 | if (pctx == NULL) { |
112 | 0 | SSH_LOG(SSH_LOG_TRACE, |
113 | 0 | "Failed to initialize X25519 context: %s", |
114 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
115 | 0 | goto out; |
116 | 0 | } |
117 | | |
118 | 0 | rc = EVP_PKEY_derive_init(pctx); |
119 | 0 | if (rc != 1) { |
120 | 0 | SSH_LOG(SSH_LOG_TRACE, |
121 | 0 | "Failed to initialize X25519 key derivation: %s", |
122 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
123 | 0 | goto out; |
124 | 0 | } |
125 | | |
126 | 0 | pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, |
127 | 0 | NULL, |
128 | 0 | *peer_pubkey_loc, |
129 | 0 | CURVE25519_PUBKEY_SIZE); |
130 | 0 | if (pubkey == NULL) { |
131 | 0 | SSH_LOG(SSH_LOG_TRACE, |
132 | 0 | "Failed to create X25519 public key EVP_PKEY: %s", |
133 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
134 | 0 | goto out; |
135 | 0 | } |
136 | | |
137 | 0 | rc = EVP_PKEY_derive_set_peer(pctx, pubkey); |
138 | 0 | if (rc != 1) { |
139 | 0 | SSH_LOG(SSH_LOG_TRACE, |
140 | 0 | "Failed to set peer X25519 public key: %s", |
141 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
142 | 0 | goto out; |
143 | 0 | } |
144 | | |
145 | 0 | rc = EVP_PKEY_derive(pctx, k, &shared_key_len); |
146 | 0 | if (rc != 1) { |
147 | 0 | SSH_LOG(SSH_LOG_TRACE, |
148 | 0 | "Failed to derive X25519 shared secret: %s", |
149 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
150 | 0 | goto out; |
151 | 0 | } |
152 | 0 | ret = SSH_OK; |
153 | |
|
154 | 0 | out: |
155 | 0 | EVP_PKEY_free(pubkey); |
156 | 0 | EVP_PKEY_CTX_free(pctx); |
157 | 0 | return ret; |
158 | 0 | } |