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-2025 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.5.2
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-v01@openssh.com"))
243  {
244  //Select the relevant hash algorithm
245  hashAlgo = SHA256_HASH_ALGO;
246  }
247  else
248 #endif
249 #if (SSH_SHA512_SUPPORT == ENABLED)
250  //RSA with SHA-512 public key algorithm?
251  if(sshCompareString(publicKeyAlgo, "rsa-sha2-512") ||
252  sshCompareString(publicKeyAlgo, "rsa-sha2-512-cert-v01@openssh.com"))
253  {
254  //Select the relevant hash algorithm
255  hashAlgo = SHA512_HASH_ALGO;
256  }
257  else
258 #endif
259  //Unknown public key algorithm?
260  {
261  //Just for sanity
262  hashAlgo = NULL;
263  }
264 
265  //Make sure the hash algorithm is supported
266  if(hashAlgo != NULL)
267  {
268  RsaPublicKey rsaPublicKey;
269 
270  //Initialize RSA public key
271  rsaInitPublicKey(&rsaPublicKey);
272 
273  //Initialize hash context
274  hashAlgo->init(&hashContext);
275 
276  //Valid session identifier?
277  if(sessionId != NULL)
278  {
279  uint8_t temp[4];
280 
281  //Encode the length of the session identifier as a 32-bit big-endian
282  //integer
283  STORE32BE(sessionId->length, temp);
284 
285  //Digest the length field
286  hashAlgo->update(&hashContext, temp, sizeof(temp));
287  //Digest the session identifier
288  hashAlgo->update(&hashContext, sessionId->value, sessionId->length);
289  }
290 
291  //Digest the message
292  hashAlgo->update(&hashContext, message->value, message->length);
293  hashAlgo->final(&hashContext, digest);
294 
295 #if (SSH_CERT_SUPPORT == ENABLED)
296  //RSA certificate?
297  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
298  {
299  SshCertificate cert;
300 
301  //Parse RSA certificate structure
302  error = sshParseCertificate(publicKeyBlob->value,
303  publicKeyBlob->length, &cert);
304 
305  //Check status
306  if(!error)
307  {
308  //Import RSA public key
309  error = sshImportRsaCertPublicKey(&rsaPublicKey, &cert);
310  }
311  }
312  else
313 #endif
314  //RSA public key?
315  {
316  SshRsaHostKey hostKey;
317 
318  //Parse RSA host key structure
319  error = sshParseRsaHostKey(publicKeyBlob->value, publicKeyBlob->length,
320  &hostKey);
321 
322  //Check status code
323  if(!error)
324  {
325  //Import RSA public key
326  error = sshImportRsaHostKey(&rsaPublicKey, &hostKey);
327  }
328  }
329 
330  //Check status code
331  if(!error)
332  {
333  //Verify RSA signature
334  error = rsassaPkcs1v15Verify(&rsaPublicKey, hashAlgo, digest,
335  signatureBlob->value, signatureBlob->length);
336  }
337 
338  //Free previously allocated resources
339  rsaFreePublicKey(&rsaPublicKey);
340  }
341  else
342  {
343  //Report an error
345  }
346 
347  //Return status code
348  return error;
349 #else
350  //Not implemented
351  return ERROR_NOT_IMPLEMENTED;
352 #endif
353 }
354 
355 
356 /**
357  * @brief DSA signature verification
358  * @param[in] publicKeyAlgo Public key algorithm
359  * @param[in] publicKeyBlob Signer's public key
360  * @param[in] sessionId Session identifier (optional parameter)
361  * @param[in] message Message whose signature is to be verified
362  * @param[in] signatureBlob Signature to be verified
363  * @return Error code
364  **/
365 
367  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
368  const SshBinaryString *message, const SshBinaryString *signatureBlob)
369 {
370 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
371  error_t error;
372  DsaPublicKey dsaPublicKey;
373  DsaSignature dsaSignature;
374  Sha1Context sha1Context;
375  uint8_t digest[SHA1_DIGEST_SIZE];
376 
377  //The DSA signature blob contains R followed by S (which are 160-bit
378  //integers)
379  if(signatureBlob->length == (2 * SHA1_DIGEST_SIZE))
380  {
381  //Initialize DSA public key
382  dsaInitPublicKey(&dsaPublicKey);
383  //Initialize DSA signature
384  dsaInitSignature(&dsaSignature);
385 
386  //Initialize hash context
387  sha1Init(&sha1Context);
388 
389  //Valid session identifier?
390  if(sessionId != NULL)
391  {
392  uint8_t temp[4];
393 
394  //Encode the length of the session identifier as a 32-bit big-endian
395  //integer
396  STORE32BE(sessionId->length, temp);
397 
398  //Digest the length field
399  sha1Update(&sha1Context, temp, sizeof(temp));
400  //Digest the session identifier
401  sha1Update(&sha1Context, sessionId->value, sessionId->length);
402  }
403 
404  //Digest the message
405  sha1Update(&sha1Context, message->value, message->length);
406  sha1Final(&sha1Context, digest);
407 
408 #if (SSH_CERT_SUPPORT == ENABLED)
409  //DSA certificate?
410  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
411  {
412  SshCertificate cert;
413 
414  //Parse DSA certificate structure
415  error = sshParseCertificate(publicKeyBlob->value,
416  publicKeyBlob->length, &cert);
417 
418  //Check status
419  if(!error)
420  {
421  //Import DSA public key
422  error = sshImportDsaCertPublicKey(&dsaPublicKey, &cert);
423  }
424  }
425  else
426 #endif
427  //DSA public key?
428  {
429  SshDsaHostKey hostKey;
430 
431  //Parse DSA host key structure
432  error = sshParseDsaHostKey(publicKeyBlob->value, publicKeyBlob->length,
433  &hostKey);
434 
435  //Check status code
436  if(!error)
437  {
438  //Import DSA public key
439  error = sshImportDsaHostKey(&dsaPublicKey, &hostKey);
440  }
441  }
442 
443  //Check status code
444  if(!error)
445  {
446  //Import integer R
447  error = mpiImport(&dsaSignature.r, signatureBlob->value,
449  }
450 
451  //Check status code
452  if(!error)
453  {
454  //Import integer S
455  error = mpiImport(&dsaSignature.s, signatureBlob->value +
457  }
458 
459  //Check status code
460  if(!error)
461  {
462  //Verify DSA signature
463  error = dsaVerifySignature(&dsaPublicKey, digest, SHA1_DIGEST_SIZE,
464  &dsaSignature);
465  }
466 
467  //Free previously allocated resources
468  dsaFreePublicKey(&dsaPublicKey);
469  dsaFreeSignature(&dsaSignature);
470  }
471  else
472  {
473  //The length of the signature is not acceptable
474  error = ERROR_INVALID_MESSAGE;
475  }
476 
477  //Return status code
478  return error;
479 #else
480  //Not implemented
481  return ERROR_NOT_IMPLEMENTED;
482 #endif
483 }
484 
485 
486 /**
487  * @brief ECDSA signature verification
488  * @param[in] publicKeyAlgo Public key algorithm
489  * @param[in] publicKeyBlob Signer's public key
490  * @param[in] sessionId Session identifier (optional parameter)
491  * @param[in] message Message whose signature is to be verified
492  * @param[in] signatureBlob Signature to be verified
493  * @return Error code
494  **/
495 
497  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
498  const SshBinaryString *message, const SshBinaryString *signatureBlob)
499 {
500 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
501  error_t error;
502  SshEcdsaSignature signature;
503  const HashAlgo *hashAlgo;
504  HashContext hashContext;
505  uint8_t digest[SSH_MAX_HASH_DIGEST_SIZE];
506 
507 #if (SSH_NISTP256_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
508  //ECDSA with NIST P-256 public key algorithm?
509  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256") ||
510  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256-cert") ||
511  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256-cert-v01@openssh.com"))
512  {
513  //Select the relevant hash algorithm
514  hashAlgo = SHA256_HASH_ALGO;
515  }
516  else
517 #endif
518 #if (SSH_NISTP384_SUPPORT == ENABLED && SSH_SHA384_SUPPORT == ENABLED)
519  //ECDSA with NIST P-384 public key algorithm?
520  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384") ||
521  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384-cert") ||
522  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384-cert-v01@openssh.com"))
523  {
524  //Select the relevant hash algorithm
525  hashAlgo = SHA384_HASH_ALGO;
526  }
527  else
528 #endif
529 #if (SSH_NISTP521_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
530  //ECDSA with NIST P-521 public key algorithm?
531  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521") ||
532  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521-cert") ||
533  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521-cert-v01@openssh.com"))
534  {
535  //Select the relevant hash algorithm
536  hashAlgo = SHA512_HASH_ALGO;
537  }
538  else
539 #endif
540  //Unknown public key algorithm?
541  {
542  //Just for sanity
543  hashAlgo = NULL;
544  }
545 
546  //Make sure the hash algorithm is supported
547  if(hashAlgo != NULL)
548  {
549  EcPublicKey ecPublicKey;
550  EcdsaSignature ecdsaSignature;
551 
552  //Initialize ECDSA public key
553  ecInitPublicKey(&ecPublicKey);
554  //Initialize ECDSA signature
555  ecdsaInitSignature(&ecdsaSignature);
556 
557  //Initialize hash context
558  hashAlgo->init(&hashContext);
559 
560  //Valid session identifier?
561  if(sessionId != NULL)
562  {
563  uint8_t temp[4];
564 
565  //Encode the length of the session identifier as a 32-bit big-endian
566  //integer
567  STORE32BE(sessionId->length, temp);
568 
569  //Digest the length field
570  hashAlgo->update(&hashContext, temp, sizeof(temp));
571  //Digest the session identifier
572  hashAlgo->update(&hashContext, sessionId->value, sessionId->length);
573  }
574 
575  //Digest the message
576  hashAlgo->update(&hashContext, message->value, message->length);
577  hashAlgo->final(&hashContext, digest);
578 
579 #if (SSH_CERT_SUPPORT == ENABLED)
580  //ECDSA certificate?
581  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
582  {
583  SshCertificate cert;
584 
585  //Parse ECDSA certificate structure
586  error = sshParseCertificate(publicKeyBlob->value,
587  publicKeyBlob->length, &cert);
588 
589  //Check status
590  if(!error)
591  {
592  //Import ECDSA public key
593  error = sshImportEcdsaCertPublicKey(&ecPublicKey, &cert);
594  }
595  }
596  else
597 #endif
598  //ECDSA public key?
599  {
600  SshEcdsaHostKey hostKey;
601 
602  //Parse ECDSA host key structure
603  error = sshParseEcdsaHostKey(publicKeyBlob->value,
604  publicKeyBlob->length, &hostKey);
605 
606  //Check status code
607  if(!error)
608  {
609  //Import ECDSA public key
610  error = sshImportEcdsaHostKey(&ecPublicKey, &hostKey);
611  }
612  }
613 
614  //Check status code
615  if(!error)
616  {
617  //Parse ECDSA signature structure
618  error = sshParseEcdsaSignature(signatureBlob->value,
619  signatureBlob->length, &signature);
620  }
621 
622  //Check status code
623  if(!error)
624  {
625  //Import integer R
626  error = ecdsaImportSignature(&ecdsaSignature, ecPublicKey.curve,
627  signature.r.value, signature.r.length, ECDSA_SIGNATURE_FORMAT_RAW_R);
628  }
629 
630  //Check status code
631  if(!error)
632  {
633  //Import integer S
634  error = ecdsaImportSignature(&ecdsaSignature, ecPublicKey.curve,
635  signature.s.value, signature.s.length, ECDSA_SIGNATURE_FORMAT_RAW_S);
636  }
637 
638  //Check status code
639  if(!error)
640  {
641  //Verify ECDSA signature
642  error = ecdsaVerifySignature(&ecPublicKey, digest,
643  hashAlgo->digestSize, &ecdsaSignature);
644  }
645 
646  //Free previously allocated resources
647  ecFreePublicKey(&ecPublicKey);
648  ecdsaFreeSignature(&ecdsaSignature);
649  }
650  else
651  {
652  //Report an error
654  }
655 
656  //Return status code
657  return error;
658 #else
659  //Not implemented
660  return ERROR_NOT_IMPLEMENTED;
661 #endif
662 }
663 
664 
665 /**
666  * @brief Ed25519 signature verification
667  * @param[in] publicKeyAlgo Public key algorithm
668  * @param[in] publicKeyBlob Signer's public key
669  * @param[in] sessionId Session identifier (optional parameter)
670  * @param[in] message Message whose signature is to be verified
671  * @param[in] signatureBlob Signature to be verified
672  * @return Error code
673  **/
674 
676  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
677  const SshBinaryString *message, const SshBinaryString *signatureBlob)
678 {
679 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
680  error_t error;
681  const uint8_t *ed25519PublicKey;
682  uint_t numMessageChunks;
683  DataChunk messageChunks[3];
684  uint8_t temp[4];
685 
686  //The Ed25519 signature shall consist of 32 octets
687  if(signatureBlob->length != ED25519_SIGNATURE_LEN)
689 
690 #if (SSH_CERT_SUPPORT == ENABLED)
691  //Ed25519 certificate?
692  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
693  {
694  SshCertificate cert;
695 
696  //Parse EdDSA certificate structure
697  error = sshParseCertificate(publicKeyBlob->value, publicKeyBlob->length,
698  &cert);
699 
700  //Check status
701  if(!error)
702  {
703  //The Ed25519 public key consists of 32 octets
704  ed25519PublicKey = cert.publicKey.eddsaPublicKey.q.value;
705  }
706  }
707  else
708 #endif
709  //Ed25519 public key?
710  {
711  SshEddsaHostKey hostKey;
712 
713  //Parse Ed25519 host key structure
714  error = sshParseEd25519HostKey(publicKeyBlob->value,
715  publicKeyBlob->length, &hostKey);
716 
717  //Check status
718  if(!error)
719  {
720  //The Ed25519 public key consists of 32 octets
721  ed25519PublicKey = hostKey.q.value;
722  }
723  }
724 
725  //Check status
726  if(!error)
727  {
728  //Valid session identifier?
729  if(sessionId != NULL)
730  {
731  //Encode the length of the session identifier as a 32-bit big-endian
732  //integer
733  STORE32BE(sessionId->length, temp);
734 
735  //Data to be signed is run through the EdDSA algorithm without
736  //pre-hashing
737  messageChunks[0].buffer = temp;
738  messageChunks[0].length = sizeof(temp);
739  messageChunks[1].buffer = sessionId->value;
740  messageChunks[1].length = sessionId->length;
741  messageChunks[2].buffer = message->value;
742  messageChunks[2].length = message->length;
743 
744  //Number of data chunks representing the message to be signed
745  numMessageChunks = 3;
746  }
747  else
748  {
749  //Data to be signed is run through the EdDSA algorithm without
750  //pre-hashing
751  messageChunks[0].buffer = message->value;
752  messageChunks[0].length = message->length;
753 
754  //The message fits in a single chunk
755  numMessageChunks = 1;
756  }
757 
758  //Verify Ed25519 signature (PureEdDSA mode)
759  error = ed25519VerifySignatureEx(ed25519PublicKey, messageChunks,
760  numMessageChunks, NULL, 0, 0, signatureBlob->value);
761  }
762 
763  //Return status code
764  return error;
765 #else
766  //Not implemented
767  return ERROR_NOT_IMPLEMENTED;
768 #endif
769 }
770 
771 
772 /**
773  * @brief Ed448 signature verification
774  * @param[in] publicKeyAlgo Public key algorithm
775  * @param[in] publicKeyBlob Signer's public key
776  * @param[in] sessionId Session identifier (optional parameter)
777  * @param[in] message Message whose signature is to be verified
778  * @param[in] signatureBlob Signature to be verified
779  * @return Error code
780  **/
781 
783  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
784  const SshBinaryString *message, const SshBinaryString *signatureBlob)
785 {
786 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
787  error_t error;
788  const uint8_t *ed448PublicKey;
789  uint_t numMessageChunks;
790  DataChunk messageChunks[3];
791  uint8_t temp[4];
792 
793  //The Ed448 signature shall consist of 57 octets
794  if(signatureBlob->length != ED448_SIGNATURE_LEN)
796 
797 #if (SSH_CERT_SUPPORT == ENABLED)
798  //Ed448 certificate?
799  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
800  {
801  SshCertificate cert;
802 
803  //Parse EdDSA certificate structure
804  error = sshParseCertificate(publicKeyBlob->value, publicKeyBlob->length,
805  &cert);
806 
807  //Check status
808  if(!error)
809  {
810  //The Ed448 public key consists of 57 octets
811  ed448PublicKey = cert.publicKey.eddsaPublicKey.q.value;
812  }
813  }
814  else
815 #endif
816  //Ed448 public key?
817  {
818  SshEddsaHostKey hostKey;
819 
820  //Parse Ed448 host key structure
821  error = sshParseEd448HostKey(publicKeyBlob->value,
822  publicKeyBlob->length, &hostKey);
823 
824  //Check status
825  if(!error)
826  {
827  //The Ed448 public key consists of 57 octets
828  ed448PublicKey = hostKey.q.value;
829  }
830  }
831 
832  //Check status
833  if(!error)
834  {
835  //Valid session identifier?
836  if(sessionId != NULL)
837  {
838  //Encode the length of the session identifier as a 32-bit big-endian
839  //integer
840  STORE32BE(sessionId->length, temp);
841 
842  //Data to be signed is run through the EdDSA algorithm without
843  //pre-hashing
844  messageChunks[0].buffer = temp;
845  messageChunks[0].length = sizeof(temp);
846  messageChunks[1].buffer = sessionId->value;
847  messageChunks[1].length = sessionId->length;
848  messageChunks[2].buffer = message->value;
849  messageChunks[2].length = message->length;
850 
851  //Number of data chunks representing the message to be signed
852  numMessageChunks = 3;
853  }
854  else
855  {
856  //Data to be signed is run through the EdDSA algorithm without
857  //pre-hashing
858  messageChunks[0].buffer = message->value;
859  messageChunks[0].length = message->length;
860 
861  //The message fits in a single chunk
862  numMessageChunks = 1;
863  }
864 
865  //Verify Ed448 signature (PureEdDSA mode)
866  error = ed448VerifySignatureEx(ed448PublicKey, messageChunks,
867  numMessageChunks, NULL, 0, 0, signatureBlob->value);
868  }
869 
870  //Return status code
871  return error;
872 #else
873  //Not implemented
874  return ERROR_NOT_IMPLEMENTED;
875 #endif
876 }
877 
878 #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:104
Mpi s
Definition: dsa.h:87
ECDSA signature.
Definition: ecdsa.h:63
HashAlgoInit init
Definition: crypto.h:1099
Generic hash algorithm context.
#define SHA256_HASH_ALGO
Definition: sha256.h:49
uint8_t sessionId[]
Definition: tls.h:1829
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:1095
const void * buffer
Definition: crypto.h:1025
HashAlgoUpdate update
Definition: crypto.h:1100
error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
Parse a string.
Definition: ssh_misc.c:1167
#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:1680
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:86
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
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:73
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:712
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:789
const uint8_t * value
Definition: ssh_types.h:68
HashAlgoFinal final
Definition: crypto.h:1101
Data chunk descriptor.
Definition: crypto.h:1024
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:558
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.
Definition: rsa.c:1068
#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:874
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:638
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:1026
error_t sshImportEcdsaHostKey(EcPublicKey *publicKey, const SshEcdsaHostKey *hostKey)
Import a ECDSA host key.
Common interface for hash algorithms.
Definition: crypto.h:1089
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:1204
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