ssh_key_verify.c
Go to the documentation of this file.
1 /**
2  * @file ssh_key_verify.c
3  * @brief SSH host key verification
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSH Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SSH_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ssh/ssh.h"
36 #include "ssh/ssh_algorithms.h"
37 #include "ssh/ssh_key_import.h"
38 #include "ssh/ssh_key_parse.h"
39 #include "ssh/ssh_key_verify.h"
40 #include "ssh/ssh_misc.h"
41 #include "debug.h"
42 
43 //Check SSH stack configuration
44 #if (SSH_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Check if a host key is trusted
49  * @param[in] hostKey Host key to be checked
50  * @param[in] hostKeyLen Length of the host key, in bytes
51  * @param[in] trustedKey Trusted host key (SSH2 or OpenSSH format)
52  * @param[in] trustedKeyLen Length of the trusted host key
53  * @return Error code
54  **/
55 
56 error_t sshVerifyHostKey(const uint8_t *hostKey, size_t hostKeyLen,
57  const char_t *trustedKey, size_t trustedKeyLen)
58 {
59  error_t error;
60  size_t n;
61  uint8_t *buffer;
62 
63  //Retrieve the length of the public key structure
64  error = sshDecodePublicKeyFile(trustedKey, trustedKeyLen, NULL, &n);
65 
66  //Check status code
67  if(!error)
68  {
69  //Allocate a memory buffer to hold the public key structure
70  buffer = sshAllocMem(n);
71 
72  //Successful memory allocation?
73  if(buffer != NULL)
74  {
75  //Decode the content of the SSH public key file
76  error = sshDecodePublicKeyFile(trustedKey, trustedKeyLen, buffer, &n);
77 
78  //Check status code
79  if(!error)
80  {
81  //Compare host keys
82  if(hostKeyLen == n && osMemcmp(hostKey, buffer, n) == 0)
83  {
84  //The host key is trusted
85  error = NO_ERROR;
86  }
87  else
88  {
89  //The host key is unknown
90  error = ERROR_INVALID_KEY;
91  }
92  }
93 
94  //Release previously allocated memory
95  sshFreeMem(buffer);
96  }
97  else
98  {
99  //Failed to allocate memory
100  error = ERROR_OUT_OF_MEMORY;
101  }
102  }
103 
104  //Return status code
105  return error;
106 }
107 
108 
109 /**
110  * @brief Verify client's host key
111  * @param[in] connection Pointer to the SSH connection
112  * @param[in] publicKeyAlgo Public key algorithm
113  * @param[in] hostKey Client's host key
114  * @return Error code
115  **/
116 
118  const SshString *publicKeyAlgo, const SshBinaryString *hostKey)
119 {
120 #if (SSH_PUBLIC_KEY_AUTH_SUPPORT == ENABLED)
121  error_t error;
122  SshString keyFormatId;
123  SshContext *context;
124  const char_t *expectedKeyFormatId;
125 
126  //Point to the SSH context
127  context = connection->context;
128 
129  //Parse client's host key
130  error = sshParseHostKey(hostKey->value, hostKey->length, &keyFormatId);
131  //Any error to report?
132  if(error)
133  return error;
134 
135  //Each host key algorithm is associated with a particular key format
136  expectedKeyFormatId = sshGetKeyFormatId(publicKeyAlgo);
137 
138  //Check whether the supplied key is consistent with the host key algorithm
139  if(!sshCompareString(&keyFormatId, expectedKeyFormatId))
140  return ERROR_INVALID_KEY;
141 
142  //Invoke user-defined callback, if any
143  if(context->publicKeyAuthCallback != NULL)
144  {
145  //Check the host key against the server's database
146  error = context->publicKeyAuthCallback(connection, connection->user,
147  hostKey->value, hostKey->length);
148  }
149  else
150  {
151  //The client's host key cannot be verified
152  error = ERROR_INVALID_KEY;
153  }
154 
155  //Return status code
156  return error;
157 #else
158  //Public key authentication is not supported
159  return ERROR_INVALID_KEY;
160 #endif
161 }
162 
163 
164 /**
165  * @brief Verify server's host key
166  * @param[in] connection Pointer to the SSH connection
167  * @param[in] publicKeyAlgo Public key algorithm
168  * @param[in] hostKey Server's host key
169  * @return Error code
170  **/
171 
173  const SshString *publicKeyAlgo, const SshBinaryString *hostKey)
174 {
175  error_t error;
176  SshString keyFormatId;
177  SshContext *context;
178  const char_t *expectedKeyFormatId;
179 
180  //Point to the SSH context
181  context = connection->context;
182 
183  //Parse server's host key
184  error = sshParseHostKey(hostKey->value, hostKey->length, &keyFormatId);
185  //Any error to report?
186  if(error)
187  return error;
188 
189  //Each host key algorithm is associated with a particular key format
190  expectedKeyFormatId = sshGetKeyFormatId(publicKeyAlgo);
191 
192  //Check whether the supplied key is consistent with the host key algorithm
193  if(!sshCompareString(&keyFormatId, expectedKeyFormatId))
194  return ERROR_INVALID_KEY;
195 
196  //Invoke user-defined callback, if any
197  if(context->hostKeyVerifyCallback != NULL)
198  {
199  //It is recommended that the client verify that the host key sent is the
200  //server's host key (for example, using a local database)
201  error = context->hostKeyVerifyCallback(connection, hostKey->value,
202  hostKey->length);
203  }
204  else
205  {
206  //The client may accept the host key without verification, but doing so
207  //will render the protocol insecure against active attacks
208  error = ERROR_INVALID_KEY;
209  }
210 
211  //Return status code
212  return error;
213 }
214 
215 #endif
SSH host key verification.
Binary string.
Definition: ssh_types.h:67
error_t sshVerifyHostKey(const uint8_t *hostKey, size_t hostKeyLen, const char_t *trustedKey, size_t trustedKeyLen)
Check if a host key is trusted.
error_t sshVerifyServerHostKey(SshConnection *connection, const SshString *publicKeyAlgo, const SshBinaryString *hostKey)
Verify server's host key.
error_t sshVerifyClientHostKey(SshConnection *connection, const SshString *publicKeyAlgo, const SshBinaryString *hostKey)
Verify client's host key.
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
SSH key parsing.
SSH key file import functions.
bool_t sshCompareString(const SshString *string, const char_t *value)
Compare a binary string against the supplied value.
Definition: ssh_misc.c:1586
size_t length
Definition: ssh_types.h:69
const char_t * sshGetKeyFormatId(const SshString *publicKeyAlgo)
Get the key format identifier used by a given public key algorithm.
#define SshContext
Definition: ssh.h:870
error_t
Error codes.
Definition: error.h:43
error_t sshDecodePublicKeyFile(const char_t *input, size_t inputLen, uint8_t *output, size_t *outputLen)
Decode SSH public key file (SSH2 or OpenSSH format)
String.
Definition: ssh_types.h:56
const uint8_t * value
Definition: ssh_types.h:68
char char_t
Definition: compiler_port.h:48
#define sshFreeMem(p)
Definition: ssh.h:729
uint8_t n
#define SshConnection
Definition: ssh.h:874
SSH helper functions.
#define sshAllocMem(size)
Definition: ssh.h:724
error_t sshParseHostKey(const uint8_t *data, size_t length, SshString *keyFormatId)
Parse host key structure.
Definition: ssh_key_parse.c:53
Secure Shell (SSH)
SSH algorithm negotiation.
@ ERROR_INVALID_KEY
Definition: error.h:106
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.