ssh_sign_verify.c
Go to the documentation of this file.
1 /**
2  * @file ssh_sign_verify.c
3  * @brief RSA/DSA/ECDSA/EdDSA signature verification
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2026 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.6.0
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_cert_import.h"
39 #include "ssh/ssh_sign_verify.h"
40 #include "ssh/ssh_sign_misc.h"
41 #include "ssh/ssh_misc.h"
42 #include "debug.h"
43 
44 //Check SSH stack configuration
45 #if (SSH_SUPPORT == ENABLED)
46 
47 
48 /**
49  * @brief Signature verification
50  * @param[in] connection Pointer to the SSH connection
51  * @param[in] publicKeyAlgo Public key algorithm
52  * @param[in] publicKeyBlob Signer's public key
53  * @param[in] sessionId Session identifier (optional parameter)
54  * @param[in] message Message whose signature is to be verified
55  * @param[in] signature Signature to be verified
56  * @return Error code
57  **/
58 
60  const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob,
62  const SshBinaryString *signature)
63 {
64  error_t error;
65  size_t n;
66  const uint8_t *p;
67  SshString keyFormatId;
68  SshString signFormatId;
69  SshBinaryString signatureBlob;
70  const char_t *expectedKeyFormatId;
71  const char_t *expectedSignFormatId;
72 
73  //Point to the first field of the signature
74  p = signature->value;
75  n = signature->length;
76 
77  //Decode signature format identifier
78  error = sshParseString(p, n, &signFormatId);
79  //Any error to report?
80  if(error)
81  return error;
82 
83  //Point to the next field
84  p += sizeof(uint32_t) + signFormatId.length;
85  n -= sizeof(uint32_t) + signFormatId.length;
86 
87  //Decode signature blob
88  error = sshParseBinaryString(p, n, &signatureBlob);
89  //Any error to report?
90  if(error)
91  return error;
92 
93  //Point to the next field
94  p += sizeof(uint32_t) + signatureBlob.length;
95  n -= sizeof(uint32_t) + signatureBlob.length;
96 
97  //Malformed signature?
98  if(n != 0)
99  return ERROR_INVALID_MESSAGE;
100 
101  //Extract key format identifier from public key blob
102  error = sshParseString(publicKeyBlob->value, publicKeyBlob->length,
103  &keyFormatId);
104  //Any error to report?
105  if(error)
106  return error;
107 
108  //Each public key algorithm is associated with a particular key format
109  expectedKeyFormatId = sshGetKeyFormatId(publicKeyAlgo);
110 
111  //Inconsistent key format identifier?
112  if(!sshCompareString(&keyFormatId, expectedKeyFormatId))
114 
115  //Public key/certificate formats that do not explicitly specify a signature
116  //format identifier must use the public key/certificate format identifier
117  //as the signature identifier (refer to RFC 4253, section 6.6)
118  expectedSignFormatId = sshGetSignFormatId(publicKeyAlgo);
119 
120  //Inconsistent signature format identifier?
121  if(!sshCompareString(&signFormatId, expectedSignFormatId))
123 
124 #if (SSH_SIGN_CALLBACK_SUPPORT == ENABLED)
125  //Valid signature verification callback function?
126  if(connection->context->signVerifyCallback != NULL)
127  {
128  //Invoke user-defined callback
129  error = connection->context->signVerifyCallback(connection,
130  publicKeyAlgo, publicKeyBlob, sessionId, message, &signatureBlob);
131  }
132  else
133 #endif
134  {
135  //No callback function registered
137  }
138 
139  //Check status code
141  {
142 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
143  //RSA signature algorithm?
144  if(sshCompareString(&signFormatId, "ssh-rsa") ||
145  sshCompareString(&signFormatId, "rsa-sha2-256") ||
146  sshCompareString(&signFormatId, "rsa-sha2-512"))
147  {
148  //RSA signature verification
149  error = sshVerifyRsaSignature(publicKeyAlgo, publicKeyBlob,
150  sessionId, message, &signatureBlob);
151  }
152  else
153 #endif
154 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
155  //DSA signature algorithm?
156  if(sshCompareString(&signFormatId, "ssh-dss"))
157  {
158  //DSA signature verification
159  error = sshVerifyDsaSignature(publicKeyAlgo, publicKeyBlob,
160  sessionId, message, &signatureBlob);
161  }
162  else
163 #endif
164 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
165  //ECDSA signature algorithm?
166  if(sshCompareString(&signFormatId, "ecdsa-sha2-nistp256") ||
167  sshCompareString(&signFormatId, "ecdsa-sha2-nistp384") ||
168  sshCompareString(&signFormatId, "ecdsa-sha2-nistp521"))
169  {
170  //ECDSA signature verification
171  error = sshVerifyEcdsaSignature(publicKeyAlgo, publicKeyBlob,
172  sessionId, message, &signatureBlob);
173  }
174  else
175 #endif
176 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
177  //Ed25519 signature algorithm?
178  if(sshCompareString(&signFormatId, "ssh-ed25519"))
179  {
180  //Ed25519 signature verification
181  error = sshVerifyEd25519Signature(publicKeyAlgo, publicKeyBlob,
182  sessionId, message, &signatureBlob);
183  }
184  else
185 #endif
186 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
187  //Ed448 signature algorithm?
188  if(sshCompareString(&signFormatId, "ssh-ed448"))
189  {
190  //Ed448 signature verification
191  error = sshVerifyEd448Signature(publicKeyAlgo, publicKeyBlob,
192  sessionId, message, &signatureBlob);
193  }
194  else
195 #endif
196  //Unknown public key type?
197  {
198  //Report an error
200  }
201  }
202 
203  //Return status code
204  return error;
205 }
206 
207 
208 /**
209  * @brief RSA signature verification
210  * @param[in] publicKeyAlgo Public key algorithm
211  * @param[in] publicKeyBlob Signer's public key
212  * @param[in] sessionId Session identifier (optional parameter)
213  * @param[in] message Message whose signature is to be verified
214  * @param[in] signatureBlob Signature to be verified
215  * @return Error code
216  **/
217 
219  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
220  const SshBinaryString *message, const SshBinaryString *signatureBlob)
221 {
222 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
223  error_t error;
224  const HashAlgo *hashAlgo;
225  HashContext hashContext;
226  uint8_t digest[SSH_MAX_HASH_DIGEST_SIZE];
227 
228 #if (SSH_SHA1_SUPPORT == ENABLED)
229  //RSA with SHA-1 public key algorithm?
230  if(sshCompareString(publicKeyAlgo, "ssh-rsa") ||
231  sshCompareString(publicKeyAlgo, "ssh-rsa-cert") ||
232  sshCompareString(publicKeyAlgo, "ssh-rsa-cert-v01@openssh.com"))
233  {
234  //Select the relevant hash algorithm
235  hashAlgo = SHA1_HASH_ALGO;
236  }
237  else
238 #endif
239 #if (SSH_SHA256_SUPPORT == ENABLED)
240  //RSA with SHA-256 public key algorithm?
241  if(sshCompareString(publicKeyAlgo, "rsa-sha2-256") ||
242  sshCompareString(publicKeyAlgo, "rsa-sha2-256-cert") ||
243  sshCompareString(publicKeyAlgo, "rsa-sha2-256-cert-v01@openssh.com"))
244  {
245  //Select the relevant hash algorithm
246  hashAlgo = SHA256_HASH_ALGO;
247  }
248  else
249 #endif
250 #if (SSH_SHA512_SUPPORT == ENABLED)
251  //RSA with SHA-512 public key algorithm?
252  if(sshCompareString(publicKeyAlgo, "rsa-sha2-512") ||
253  sshCompareString(publicKeyAlgo, "rsa-sha2-512-cert") ||
254  sshCompareString(publicKeyAlgo, "rsa-sha2-512-cert-v01@openssh.com"))
255  {
256  //Select the relevant hash algorithm
257  hashAlgo = SHA512_HASH_ALGO;
258  }
259  else
260 #endif
261  //Unknown public key algorithm?
262  {
263  //Just for sanity
264  hashAlgo = NULL;
265  }
266 
267  //Make sure the hash algorithm is supported
268  if(hashAlgo != NULL)
269  {
270  RsaPublicKey rsaPublicKey;
271 
272  //Initialize RSA public key
273  rsaInitPublicKey(&rsaPublicKey);
274 
275  //Initialize hash context
276  hashAlgo->init(&hashContext);
277 
278  //Valid session identifier?
279  if(sessionId != NULL)
280  {
281  uint8_t temp[4];
282 
283  //Encode the length of the session identifier as a 32-bit big-endian
284  //integer
285  STORE32BE(sessionId->length, temp);
286 
287  //Digest the length field
288  hashAlgo->update(&hashContext, temp, sizeof(temp));
289  //Digest the session identifier
290  hashAlgo->update(&hashContext, sessionId->value, sessionId->length);
291  }
292 
293  //Digest the message
294  hashAlgo->update(&hashContext, message->value, message->length);
295  hashAlgo->final(&hashContext, digest);
296 
297 #if (SSH_CERT_SUPPORT == ENABLED)
298  //RSA certificate?
299  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
300  {
301  SshCertificate cert;
302 
303  //Parse RSA certificate structure
304  error = sshParseCertificate(publicKeyBlob->value,
305  publicKeyBlob->length, &cert);
306 
307  //Check status
308  if(!error)
309  {
310  //Import RSA public key
311  error = sshImportRsaCertPublicKey(&rsaPublicKey, &cert);
312  }
313  }
314  else
315 #endif
316  //RSA public key?
317  {
318  SshRsaHostKey hostKey;
319 
320  //Parse RSA host key structure
321  error = sshParseRsaHostKey(publicKeyBlob->value, publicKeyBlob->length,
322  &hostKey);
323 
324  //Check status code
325  if(!error)
326  {
327  //Import RSA public key
328  error = sshImportRsaHostKey(&rsaPublicKey, &hostKey);
329  }
330  }
331 
332  //Check status code
333  if(!error)
334  {
335  //Verify RSA signature
336  error = rsassaPkcs1v15Verify(&rsaPublicKey, hashAlgo, digest,
337  signatureBlob->value, signatureBlob->length);
338  }
339 
340  //Free previously allocated resources
341  rsaFreePublicKey(&rsaPublicKey);
342  }
343  else
344  {
345  //Report an error
347  }
348 
349  //Return status code
350  return error;
351 #else
352  //Not implemented
353  return ERROR_NOT_IMPLEMENTED;
354 #endif
355 }
356 
357 
358 /**
359  * @brief DSA signature verification
360  * @param[in] publicKeyAlgo Public key algorithm
361  * @param[in] publicKeyBlob Signer's public key
362  * @param[in] sessionId Session identifier (optional parameter)
363  * @param[in] message Message whose signature is to be verified
364  * @param[in] signatureBlob Signature to be verified
365  * @return Error code
366  **/
367 
369  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
370  const SshBinaryString *message, const SshBinaryString *signatureBlob)
371 {
372 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
373  error_t error;
374  DsaPublicKey dsaPublicKey;
375  DsaSignature dsaSignature;
376  Sha1Context sha1Context;
377  uint8_t digest[SHA1_DIGEST_SIZE];
378 
379  //The DSA signature blob contains R followed by S (which are 160-bit
380  //integers)
381  if(signatureBlob->length == (2 * SHA1_DIGEST_SIZE))
382  {
383  //Initialize DSA public key
384  dsaInitPublicKey(&dsaPublicKey);
385  //Initialize DSA signature
386  dsaInitSignature(&dsaSignature);
387 
388  //Initialize hash context
389  sha1Init(&sha1Context);
390 
391  //Valid session identifier?
392  if(sessionId != NULL)
393  {
394  uint8_t temp[4];
395 
396  //Encode the length of the session identifier as a 32-bit big-endian
397  //integer
398  STORE32BE(sessionId->length, temp);
399 
400  //Digest the length field
401  sha1Update(&sha1Context, temp, sizeof(temp));
402  //Digest the session identifier
403  sha1Update(&sha1Context, sessionId->value, sessionId->length);
404  }
405 
406  //Digest the message
407  sha1Update(&sha1Context, message->value, message->length);
408  sha1Final(&sha1Context, digest);
409 
410 #if (SSH_CERT_SUPPORT == ENABLED)
411  //DSA certificate?
412  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
413  {
414  SshCertificate cert;
415 
416  //Parse DSA certificate structure
417  error = sshParseCertificate(publicKeyBlob->value,
418  publicKeyBlob->length, &cert);
419 
420  //Check status
421  if(!error)
422  {
423  //Import DSA public key
424  error = sshImportDsaCertPublicKey(&dsaPublicKey, &cert);
425  }
426  }
427  else
428 #endif
429  //DSA public key?
430  {
431  SshDsaHostKey hostKey;
432 
433  //Parse DSA host key structure
434  error = sshParseDsaHostKey(publicKeyBlob->value, publicKeyBlob->length,
435  &hostKey);
436 
437  //Check status code
438  if(!error)
439  {
440  //Import DSA public key
441  error = sshImportDsaHostKey(&dsaPublicKey, &hostKey);
442  }
443  }
444 
445  //Check status code
446  if(!error)
447  {
448  //Import integer R
449  error = mpiImport(&dsaSignature.r, signatureBlob->value,
451  }
452 
453  //Check status code
454  if(!error)
455  {
456  //Import integer S
457  error = mpiImport(&dsaSignature.s, signatureBlob->value +
459  }
460 
461  //Check status code
462  if(!error)
463  {
464  //Verify DSA signature
465  error = dsaVerifySignature(&dsaPublicKey, digest, SHA1_DIGEST_SIZE,
466  &dsaSignature);
467  }
468 
469  //Free previously allocated resources
470  dsaFreePublicKey(&dsaPublicKey);
471  dsaFreeSignature(&dsaSignature);
472  }
473  else
474  {
475  //The length of the signature is not acceptable
476  error = ERROR_INVALID_MESSAGE;
477  }
478 
479  //Return status code
480  return error;
481 #else
482  //Not implemented
483  return ERROR_NOT_IMPLEMENTED;
484 #endif
485 }
486 
487 
488 /**
489  * @brief ECDSA signature verification
490  * @param[in] publicKeyAlgo Public key algorithm
491  * @param[in] publicKeyBlob Signer's public key
492  * @param[in] sessionId Session identifier (optional parameter)
493  * @param[in] message Message whose signature is to be verified
494  * @param[in] signatureBlob Signature to be verified
495  * @return Error code
496  **/
497 
499  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
500  const SshBinaryString *message, const SshBinaryString *signatureBlob)
501 {
502 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
503  error_t error;
504  SshEcdsaSignature signature;
505  const HashAlgo *hashAlgo;
506  HashContext hashContext;
507  uint8_t digest[SSH_MAX_HASH_DIGEST_SIZE];
508 
509 #if (SSH_NISTP256_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
510  //ECDSA with NIST P-256 public key algorithm?
511  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256") ||
512  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256-cert") ||
513  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256-cert-v01@openssh.com"))
514  {
515  //Select the relevant hash algorithm
516  hashAlgo = SHA256_HASH_ALGO;
517  }
518  else
519 #endif
520 #if (SSH_NISTP384_SUPPORT == ENABLED && SSH_SHA384_SUPPORT == ENABLED)
521  //ECDSA with NIST P-384 public key algorithm?
522  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384") ||
523  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384-cert") ||
524  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384-cert-v01@openssh.com"))
525  {
526  //Select the relevant hash algorithm
527  hashAlgo = SHA384_HASH_ALGO;
528  }
529  else
530 #endif
531 #if (SSH_NISTP521_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
532  //ECDSA with NIST P-521 public key algorithm?
533  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521") ||
534  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521-cert") ||
535  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521-cert-v01@openssh.com"))
536  {
537  //Select the relevant hash algorithm
538  hashAlgo = SHA512_HASH_ALGO;
539  }
540  else
541 #endif
542  //Unknown public key algorithm?
543  {
544  //Just for sanity
545  hashAlgo = NULL;
546  }
547 
548  //Make sure the hash algorithm is supported
549  if(hashAlgo != NULL)
550  {
551  EcPublicKey ecPublicKey;
552  EcdsaSignature ecdsaSignature;
553 
554  //Initialize ECDSA public key
555  ecInitPublicKey(&ecPublicKey);
556  //Initialize ECDSA signature
557  ecdsaInitSignature(&ecdsaSignature);
558 
559  //Initialize hash context
560  hashAlgo->init(&hashContext);
561 
562  //Valid session identifier?
563  if(sessionId != NULL)
564  {
565  uint8_t temp[4];
566 
567  //Encode the length of the session identifier as a 32-bit big-endian
568  //integer
569  STORE32BE(sessionId->length, temp);
570 
571  //Digest the length field
572  hashAlgo->update(&hashContext, temp, sizeof(temp));
573  //Digest the session identifier
574  hashAlgo->update(&hashContext, sessionId->value, sessionId->length);
575  }
576 
577  //Digest the message
578  hashAlgo->update(&hashContext, message->value, message->length);
579  hashAlgo->final(&hashContext, digest);
580 
581 #if (SSH_CERT_SUPPORT == ENABLED)
582  //ECDSA certificate?
583  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
584  {
585  SshCertificate cert;
586 
587  //Parse ECDSA certificate structure
588  error = sshParseCertificate(publicKeyBlob->value,
589  publicKeyBlob->length, &cert);
590 
591  //Check status
592  if(!error)
593  {
594  //Import ECDSA public key
595  error = sshImportEcdsaCertPublicKey(&ecPublicKey, &cert);
596  }
597  }
598  else
599 #endif
600  //ECDSA public key?
601  {
602  SshEcdsaHostKey hostKey;
603 
604  //Parse ECDSA host key structure
605  error = sshParseEcdsaHostKey(publicKeyBlob->value,
606  publicKeyBlob->length, &hostKey);
607 
608  //Check status code
609  if(!error)
610  {
611  //Import ECDSA public key
612  error = sshImportEcdsaHostKey(&ecPublicKey, &hostKey);
613  }
614  }
615 
616  //Check status code
617  if(!error)
618  {
619  //Parse ECDSA signature structure
620  error = sshParseEcdsaSignature(signatureBlob->value,
621  signatureBlob->length, &signature);
622  }
623 
624  //Check status code
625  if(!error)
626  {
627  //Import integer R
628  error = ecdsaImportSignature(&ecdsaSignature, ecPublicKey.curve,
629  signature.r.value, signature.r.length, ECDSA_SIGNATURE_FORMAT_RAW_R);
630  }
631 
632  //Check status code
633  if(!error)
634  {
635  //Import integer S
636  error = ecdsaImportSignature(&ecdsaSignature, ecPublicKey.curve,
637  signature.s.value, signature.s.length, ECDSA_SIGNATURE_FORMAT_RAW_S);
638  }
639 
640  //Check status code
641  if(!error)
642  {
643  //Verify ECDSA signature
644  error = ecdsaVerifySignature(&ecPublicKey, digest,
645  hashAlgo->digestSize, &ecdsaSignature);
646  }
647 
648  //Free previously allocated resources
649  ecFreePublicKey(&ecPublicKey);
650  ecdsaFreeSignature(&ecdsaSignature);
651  }
652  else
653  {
654  //Report an error
656  }
657 
658  //Return status code
659  return error;
660 #else
661  //Not implemented
662  return ERROR_NOT_IMPLEMENTED;
663 #endif
664 }
665 
666 
667 /**
668  * @brief Ed25519 signature verification
669  * @param[in] publicKeyAlgo Public key algorithm
670  * @param[in] publicKeyBlob Signer's public key
671  * @param[in] sessionId Session identifier (optional parameter)
672  * @param[in] message Message whose signature is to be verified
673  * @param[in] signatureBlob Signature to be verified
674  * @return Error code
675  **/
676 
678  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
679  const SshBinaryString *message, const SshBinaryString *signatureBlob)
680 {
681 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
682  error_t error;
683  const uint8_t *ed25519PublicKey;
684  uint_t numMessageChunks;
685  DataChunk messageChunks[3];
686  uint8_t temp[4];
687 
688  //The Ed25519 signature shall consist of 32 octets
689  if(signatureBlob->length != ED25519_SIGNATURE_LEN)
691 
692 #if (SSH_CERT_SUPPORT == ENABLED)
693  //Ed25519 certificate?
694  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
695  {
696  SshCertificate cert;
697 
698  //Parse EdDSA certificate structure
699  error = sshParseCertificate(publicKeyBlob->value, publicKeyBlob->length,
700  &cert);
701 
702  //Check status
703  if(!error)
704  {
705  //The Ed25519 public key consists of 32 octets
706  ed25519PublicKey = cert.publicKey.eddsaPublicKey.q.value;
707  }
708  }
709  else
710 #endif
711  //Ed25519 public key?
712  {
713  SshEddsaHostKey hostKey;
714 
715  //Parse Ed25519 host key structure
716  error = sshParseEd25519HostKey(publicKeyBlob->value,
717  publicKeyBlob->length, &hostKey);
718 
719  //Check status
720  if(!error)
721  {
722  //The Ed25519 public key consists of 32 octets
723  ed25519PublicKey = hostKey.q.value;
724  }
725  }
726 
727  //Check status
728  if(!error)
729  {
730  //Valid session identifier?
731  if(sessionId != NULL)
732  {
733  //Encode the length of the session identifier as a 32-bit big-endian
734  //integer
735  STORE32BE(sessionId->length, temp);
736 
737  //Data to be signed is run through the EdDSA algorithm without
738  //pre-hashing
739  messageChunks[0].buffer = temp;
740  messageChunks[0].length = sizeof(temp);
741  messageChunks[1].buffer = sessionId->value;
742  messageChunks[1].length = sessionId->length;
743  messageChunks[2].buffer = message->value;
744  messageChunks[2].length = message->length;
745 
746  //Number of data chunks representing the message to be signed
747  numMessageChunks = 3;
748  }
749  else
750  {
751  //Data to be signed is run through the EdDSA algorithm without
752  //pre-hashing
753  messageChunks[0].buffer = message->value;
754  messageChunks[0].length = message->length;
755 
756  //The message fits in a single chunk
757  numMessageChunks = 1;
758  }
759 
760  //Verify Ed25519 signature (PureEdDSA mode)
761  error = ed25519VerifySignatureEx(ed25519PublicKey, messageChunks,
762  numMessageChunks, NULL, 0, 0, signatureBlob->value);
763  }
764 
765  //Return status code
766  return error;
767 #else
768  //Not implemented
769  return ERROR_NOT_IMPLEMENTED;
770 #endif
771 }
772 
773 
774 /**
775  * @brief Ed448 signature verification
776  * @param[in] publicKeyAlgo Public key algorithm
777  * @param[in] publicKeyBlob Signer's public key
778  * @param[in] sessionId Session identifier (optional parameter)
779  * @param[in] message Message whose signature is to be verified
780  * @param[in] signatureBlob Signature to be verified
781  * @return Error code
782  **/
783 
785  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
786  const SshBinaryString *message, const SshBinaryString *signatureBlob)
787 {
788 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
789  error_t error;
790  const uint8_t *ed448PublicKey;
791  uint_t numMessageChunks;
792  DataChunk messageChunks[3];
793  uint8_t temp[4];
794 
795  //The Ed448 signature shall consist of 57 octets
796  if(signatureBlob->length != ED448_SIGNATURE_LEN)
798 
799 #if (SSH_CERT_SUPPORT == ENABLED)
800  //Ed448 certificate?
801  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
802  {
803  SshCertificate cert;
804 
805  //Parse EdDSA certificate structure
806  error = sshParseCertificate(publicKeyBlob->value, publicKeyBlob->length,
807  &cert);
808 
809  //Check status
810  if(!error)
811  {
812  //The Ed448 public key consists of 57 octets
813  ed448PublicKey = cert.publicKey.eddsaPublicKey.q.value;
814  }
815  }
816  else
817 #endif
818  //Ed448 public key?
819  {
820  SshEddsaHostKey hostKey;
821 
822  //Parse Ed448 host key structure
823  error = sshParseEd448HostKey(publicKeyBlob->value,
824  publicKeyBlob->length, &hostKey);
825 
826  //Check status
827  if(!error)
828  {
829  //The Ed448 public key consists of 57 octets
830  ed448PublicKey = hostKey.q.value;
831  }
832  }
833 
834  //Check status
835  if(!error)
836  {
837  //Valid session identifier?
838  if(sessionId != NULL)
839  {
840  //Encode the length of the session identifier as a 32-bit big-endian
841  //integer
842  STORE32BE(sessionId->length, temp);
843 
844  //Data to be signed is run through the EdDSA algorithm without
845  //pre-hashing
846  messageChunks[0].buffer = temp;
847  messageChunks[0].length = sizeof(temp);
848  messageChunks[1].buffer = sessionId->value;
849  messageChunks[1].length = sessionId->length;
850  messageChunks[2].buffer = message->value;
851  messageChunks[2].length = message->length;
852 
853  //Number of data chunks representing the message to be signed
854  numMessageChunks = 3;
855  }
856  else
857  {
858  //Data to be signed is run through the EdDSA algorithm without
859  //pre-hashing
860  messageChunks[0].buffer = message->value;
861  messageChunks[0].length = message->length;
862 
863  //The message fits in a single chunk
864  numMessageChunks = 1;
865  }
866 
867  //Verify Ed448 signature (PureEdDSA mode)
868  error = ed448VerifySignatureEx(ed448PublicKey, messageChunks,
869  numMessageChunks, NULL, 0, 0, signatureBlob->value);
870  }
871 
872  //Return status code
873  return error;
874 #else
875  //Not implemented
876  return ERROR_NOT_IMPLEMENTED;
877 #endif
878 }
879 
880 #endif
error_t ecdsaImportSignature(EcdsaSignature *signature, const EcCurve *curve, const uint8_t *input, size_t length, EcdsaSignatureFormat format)
Import an ECDSA signature.
Definition: ecdsa.c:107
Mpi s
Definition: dsa.h:87
ECDSA signature.
Definition: ecdsa.h:63
HashAlgoInit init
Definition: crypto.h:1161
Generic hash algorithm context.
#define SHA256_HASH_ALGO
Definition: sha256.h:49
uint8_t sessionId[]
Definition: tls.h:1895
void rsaFreePublicKey(RsaPublicKey *key)
Release an RSA public key.
Definition: rsa.c:113
#define SHA1_HASH_ALGO
Definition: sha1.h:49
#define SHA512_HASH_ALGO
Definition: sha512.h:49
void sha1Update(Sha1Context *context, const void *data, size_t length)
Update the SHA-1 context with a portion of the message being hashed.
error_t sshParseDsaHostKey(const uint8_t *data, size_t length, SshDsaHostKey *hostKey)
Parse a DSA host key structure.
Binary string.
Definition: ssh_types.h:67
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
DSA host key.
Definition: ssh_key_parse.h:64
uint8_t p
Definition: ndp.h:300
uint8_t message[]
Definition: chap.h:154
error_t sshParseEd448HostKey(const uint8_t *data, size_t length, SshEddsaHostKey *hostKey)
Parse an Ed448 host key structure.
size_t digestSize
Definition: crypto.h:1157
const void * buffer
Definition: crypto.h:1080
HashAlgoUpdate update
Definition: crypto.h:1162
error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
Parse a string.
Definition: ssh_misc.c:1178
#define ED448_SIGNATURE_LEN
Definition: ed448.h:44
Mpi r
Definition: dsa.h:86
SshBinaryString q
size_t length
Definition: ssh_types.h:58
#define ED25519_SIGNATURE_LEN
Definition: ed25519.h:44
error_t sshVerifyEd448Signature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
Ed448 signature verification.
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
error_t sshImportEcdsaCertPublicKey(EcPublicKey *publicKey, const SshCertificate *cert)
Import an ECDSA public key from a certificate.
error_t sshParseRsaHostKey(const uint8_t *data, size_t length, SshRsaHostKey *hostKey)
Parse an RSA host key structure.
SSH key file import functions.
error_t sshVerifyEcdsaSignature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
ECDSA signature verification.
bool_t sshCompareString(const SshString *string, const char_t *value)
Compare a binary string against the supplied value.
Definition: ssh_misc.c:1691
bool_t sshIsCertPublicKeyAlgo(const SshString *publicKeyAlgo)
Test if the specified public key algorithm is using certificates.
ECDSA signature.
Definition: ssh_sign_misc.h:48
size_t length
Definition: ssh_types.h:69
void ecdsaFreeSignature(EcdsaSignature *signature)
Release an ECDSA signature.
Definition: ecdsa.c:90
const char_t * sshGetKeyFormatId(const SshString *publicKeyAlgo)
Get the key format identifier used by a given public key algorithm.
DSA public key.
Definition: dsa.h:61
void sha1Init(Sha1Context *context)
Initialize SHA-1 message digest context.
error_t
Error codes.
Definition: error.h:43
void dsaInitSignature(DsaSignature *signature)
Initialize a DSA signature.
Definition: dsa.c:168
error_t rsassaPkcs1v15Verify(const RsaPublicKey *key, const HashAlgo *hash, const uint8_t *digest, const uint8_t *signature, size_t signatureLen)
RSASSA-PKCS1-v1_5 signature verification operation.
void ecInitPublicKey(EcPublicKey *key)
Initialize an EC public key.
Definition: ec.c:52
error_t sshVerifySignature(SshConnection *connection, const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signature)
Signature verification.
RSA public key.
Definition: rsa.h:57
void ecdsaInitSignature(EcdsaSignature *signature)
Initialize an ECDSA signature.
Definition: ecdsa.c:74
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:714
SshBinaryString s
Definition: ssh_sign_misc.h:50
error_t sshParseEcdsaHostKey(const uint8_t *data, size_t length, SshEcdsaHostKey *hostKey)
Parse an ECDSA host key structure.
error_t sshImportDsaHostKey(DsaPublicKey *publicKey, const SshDsaHostKey *hostKey)
Import a DSA host key.
error_t sshParseEd25519HostKey(const uint8_t *data, size_t length, SshEddsaHostKey *hostKey)
Parse an Ed25519 host key structure.
EdDSA host key.
Definition: ssh_key_parse.h:90
SshBinaryString r
Definition: ssh_sign_misc.h:49
String.
Definition: ssh_types.h:56
#define SSH_MAX_HASH_DIGEST_SIZE
Definition: ssh.h:796
const uint8_t * value
Definition: ssh_types.h:68
HashAlgoFinal final
Definition: crypto.h:1163
Data chunk descriptor.
Definition: crypto.h:1079
EC public key.
Definition: ec.h:421
#define SHA384_HASH_ALGO
Definition: sha384.h:45
error_t ed448VerifySignatureEx(const uint8_t *publicKey, const DataChunk *message, uint_t messageLen, const void *context, uint8_t contextLen, uint8_t flag, const uint8_t *signature)
EdDSA signature verification.
Definition: ed448.c:437
char char_t
Definition: compiler_port.h:55
error_t dsaVerifySignature(const DsaPublicKey *key, const uint8_t *digest, size_t digestLen, const DsaSignature *signature)
DSA signature verification.
Definition: dsa.c:571
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
error_t sshImportRsaHostKey(RsaPublicKey *publicKey, const SshRsaHostKey *hostKey)
Import an RSA host key.
SshCertPublicKey publicKey
uint8_t n
error_t sshParseEcdsaSignature(const uint8_t *data, size_t length, SshEcdsaSignature *signature)
Parse an ECDSA signature.
Definition: ssh_sign_misc.c:98
#define SshConnection
Definition: ssh.h:896
error_t sshParseCertificate(const uint8_t *data, size_t length, SshCertificate *cert)
Parse SSH certificate.
Helper functions for signature generation and verification.
@ ECDSA_SIGNATURE_FORMAT_RAW_R
Definition: ecdsa.h:53
ECDSA host key.
Definition: ssh_key_parse.h:78
__weak_func error_t ecdsaVerifySignature(const EcPublicKey *publicKey, const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
ECDSA signature verification.
Definition: ecdsa.c:952
void dsaFreeSignature(DsaSignature *signature)
Release a DSA signature.
Definition: dsa.c:181
SSH certificate import functions.
SSH helper functions.
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:93
RSA host key.
Definition: ssh_key_parse.h:52
SHA-1 algorithm context.
Definition: sha1.h:62
size_t length
Definition: crypto.h:1081
error_t sshImportEcdsaHostKey(EcPublicKey *publicKey, const SshEcdsaHostKey *hostKey)
Import a ECDSA host key.
Common interface for hash algorithms.
Definition: crypto.h:1151
error_t sshImportDsaCertPublicKey(DsaPublicKey *publicKey, const SshCertificate *cert)
Import a DSA public key from a certificate.
error_t sshParseBinaryString(const uint8_t *p, size_t length, SshBinaryString *string)
Parse a binary string.
Definition: ssh_misc.c:1215
DSA signature.
Definition: dsa.h:85
error_t sshVerifyRsaSignature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
RSA signature verification.
error_t sshVerifyEd25519Signature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
Ed25519 signature verification.
@ ERROR_UNSUPPORTED_SIGNATURE_ALGO
Definition: error.h:132
unsigned int uint_t
Definition: compiler_port.h:57
@ ECDSA_SIGNATURE_FORMAT_RAW_S
Definition: ecdsa.h:54
error_t sshVerifyDsaSignature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
DSA signature verification.
void sha1Final(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest.
Secure Shell (SSH)
SSH algorithm negotiation.
SshBinaryString q
Definition: ssh_key_parse.h:92
@ ERROR_INVALID_SIGNATURE
Definition: error.h:228
SshEddsaCertPublicKey eddsaPublicKey
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:422
void dsaFreePublicKey(DsaPublicKey *key)
Release a DSA public key.
Definition: dsa.c:119
RSA/DSA/ECDSA/EdDSA signature verification.
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
void dsaInitPublicKey(DsaPublicKey *key)
Initialize a DSA public key.
Definition: dsa.c:105
SSH certificate (OpenSSH format)
Debugging facilities.
void rsaInitPublicKey(RsaPublicKey *key)
Initialize an RSA public key.
Definition: rsa.c:100
void ecFreePublicKey(EcPublicKey *key)
Release an EC public key.
Definition: ec.c:68
error_t sshImportRsaCertPublicKey(RsaPublicKey *publicKey, const SshCertificate *cert)
Import an RSA public key from a certificate.
const char_t * sshGetSignFormatId(const SshString *publicKeyAlgo)
Get the signature format identifier used by a given public key algorithm.
error_t ed25519VerifySignatureEx(const uint8_t *publicKey, const DataChunk *message, uint_t messageLen, const void *context, uint8_t contextLen, uint8_t flag, const uint8_t *signature)
EdDSA signature verification.
Definition: ed25519.c:460