ssh_signature.c
Go to the documentation of this file.
1 /**
2  * @file ssh_signature.c
3  * @brief RSA/DSA/ECDSA/EdDSA signature generation and verification
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2023 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.2.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_signature.h"
38 #include "ssh/ssh_key_import.h"
39 #include "ssh/ssh_key_parse.h"
40 #include "ssh/ssh_cert_import.h"
41 #include "ssh/ssh_cert_parse.h"
42 #include "ssh/ssh_misc.h"
43 #include "ecc/ecdsa.h"
44 #include "ecc/eddsa.h"
45 #include "debug.h"
46 
47 //Check SSH stack configuration
48 #if (SSH_SUPPORT == ENABLED)
49 
50 
51 /**
52  * @brief Signature generation
53  * @param[in] connection Pointer to the SSH connection
54  * @param[in] publicKeyAlgo Public key algorithm
55  * @param[in] hostKey Pointer to the signer's host key
56  * @param[in] sessionId Session identifier (optional parameter)
57  * @param[in] message Pointer to the message to be signed
58  * @param[out] p Output stream where to write the signature
59  * @param[out] written Total number of bytes that have been written
60  * @return Error code
61  **/
62 
64  const char_t *publicKeyAlgo, const SshHostKey *hostKey,
66  uint8_t *p, size_t *written)
67 {
68  error_t error;
69  size_t n;
71  const char_t *signFormatId;
72 
73  //Total length of the signature encoding
74  *written = 0;
75 
76  //Get the name of the public key algorithm
77  name.value = publicKeyAlgo;
78  name.length = osStrlen(publicKeyAlgo);
79 
80  //Public key/certificate formats that do not explicitly specify a signature
81  //format identifier must use the public key/certificate format identifier
82  //as the signature identifier (refer to RFC 4253, section 6.6)
83  signFormatId = sshGetSignFormatId(&name);
84 
85  //Valid signature format identifier?
86  if(signFormatId != NULL)
87  {
88  //Format signature format identifier
89  error = sshFormatString(signFormatId, p, &n);
90 
91  //Check status code
92  if(!error)
93  {
94  //Point to the signature blob
95  p += n;
96  *written += n;
97 
98 #if (SSH_SIGN_CALLBACK_SUPPORT == ENABLED)
99  //Valid signature generation callback function?
100  if(connection->context->signGenCallback != NULL)
101  {
102  //Invoke user-defined callback
103  error = connection->context->signGenCallback(connection,
104  signFormatId, hostKey, sessionId, message, p, &n);
105  }
106  else
107 #endif
108  {
109  //No callback function registered
111  }
112 
113  //Check status code
114  if(error == ERROR_UNSUPPORTED_SIGNATURE_ALGO ||
115  error == ERROR_UNKOWN_KEY)
116  {
117 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
118  //RSA signature algorithm?
119  if(sshCompareAlgo(signFormatId, "ssh-rsa") ||
120  sshCompareAlgo(signFormatId, "rsa-sha2-256") ||
121  sshCompareAlgo(signFormatId, "rsa-sha2-512"))
122  {
123  //Generate an RSA signature using the host private key
124  error = sshGenerateRsaSignature(connection, signFormatId,
125  hostKey, sessionId, message, p, &n);
126  }
127  else
128 #endif
129 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
130  //DSA signature algorithm?
131  if(sshCompareAlgo(signFormatId, "ssh-dss"))
132  {
133  //Generate a DSA signature using the host private key
134  error = sshGenerateDsaSignature(connection, signFormatId,
135  hostKey, sessionId, message, p, &n);
136  }
137  else
138 #endif
139 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
140  //ECDSA signature algorithm?
141  if(sshCompareAlgo(signFormatId, "ecdsa-sha2-nistp256") ||
142  sshCompareAlgo(signFormatId, "ecdsa-sha2-nistp384") ||
143  sshCompareAlgo(signFormatId, "ecdsa-sha2-nistp521"))
144  {
145  //Generate an ECDSA signature using the host private key
146  error = sshGenerateEcdsaSignature(connection, signFormatId,
147  hostKey, sessionId, message, p, &n);
148  }
149  else
150 #endif
151 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
152  //Ed22519 signature algorithm?
153  if(sshCompareAlgo(signFormatId, "ssh-ed25519"))
154  {
155  //Generate an EdDSA signature using the host private key
156  error = sshGenerateEd25519Signature(connection, signFormatId,
157  hostKey, sessionId, message, p, &n);
158  }
159  else
160 #endif
161 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
162  //Ed448 signature algorithm?
163  if(sshCompareAlgo(signFormatId, "ssh-ed448"))
164  {
165  //Generate an EdDSA signature using the host private key
166  error = sshGenerateEd448Signature(connection, signFormatId,
167  hostKey, sessionId, message, p, &n);
168  }
169  else
170 #endif
171  //Unknown signature algorithm?
172  {
173  //Report an error
175  }
176  }
177  }
178 
179  //Check status code
180  if(!error)
181  {
182  //Total number of bytes that have been written
183  *written += n;
184  }
185  }
186  else
187  {
188  //Report an error
190  }
191 
192  //Return status code
193  return error;
194 }
195 
196 
197 /**
198  * @brief RSA signature generation
199  * @param[in] connection Pointer to the SSH connection
200  * @param[in] publicKeyAlgo Public key algorithm
201  * @param[in] hostKey Pointer to the signer's host key
202  * @param[in] sessionId Session identifier (optional parameter)
203  * @param[in] message Pointer to the message to be signed
204  * @param[out] p Output stream where to write the signature
205  * @param[out] written Total number of bytes that have been written
206  * @return Error code
207  **/
208 
210  const char_t *publicKeyAlgo, const SshHostKey *hostKey,
212  uint8_t *p, size_t *written)
213 {
214 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
215  error_t error;
216  size_t n;
217  const HashAlgo *hashAlgo;
218  HashContext hashContext;
219 
220 #if (SSH_SHA1_SUPPORT == ENABLED)
221  //RSA with SHA-1 public key algorithm?
222  if(sshCompareAlgo(publicKeyAlgo, "ssh-rsa"))
223  {
224  //Select the relevant hash algorithm
225  hashAlgo = SHA1_HASH_ALGO;
226  }
227  else
228 #endif
229 #if (SSH_SHA256_SUPPORT == ENABLED)
230  //RSA with SHA-256 public key algorithm?
231  if(sshCompareAlgo(publicKeyAlgo, "rsa-sha2-256"))
232  {
233  //Select the relevant hash algorithm
234  hashAlgo = SHA256_HASH_ALGO;
235  }
236  else
237 #endif
238 #if (SSH_SHA512_SUPPORT == ENABLED)
239  //RSA with SHA-512 public key algorithm?
240  if(sshCompareAlgo(publicKeyAlgo, "rsa-sha2-512"))
241  {
242  //Select the relevant hash algorithm
243  hashAlgo = SHA512_HASH_ALGO;
244  }
245  else
246 #endif
247  //Unknown host key algorithm?
248  {
249  //Just for sanity
250  hashAlgo = NULL;
251  }
252 
253  //Make sure the hash algorithm is supported
254  if(hashAlgo != NULL)
255  {
256  RsaPrivateKey rsaPrivateKey;
257 
258  //Initialize RSA private key
259  rsaInitPrivateKey(&rsaPrivateKey);
260 
261  //Initialize hash context
262  hashAlgo->init(&hashContext);
263 
264  //Valid session identifier?
265  if(sessionId != NULL)
266  {
267  uint8_t temp[4];
268 
269  //Encode the length of the session identifier as a 32-bit big-endian
270  //integer
271  STORE32BE(sessionId->length, temp);
272 
273  //Digest the length field
274  hashAlgo->update(&hashContext, temp, sizeof(temp));
275  //Digest the session identifier
276  hashAlgo->update(&hashContext, sessionId->value, sessionId->length);
277  }
278 
279  //Digest the message
280  hashAlgo->update(&hashContext, message->value, message->length);
281  hashAlgo->final(&hashContext, NULL);
282 
283  //Import RSA private key
284  error = sshImportRsaPrivateKey(hostKey->privateKey,
285  hostKey->privateKeyLen, hostKey->password, &rsaPrivateKey);
286 
287  //Check status code
288  if(!error)
289  {
290  //Generate RSA signature
291  error = rsassaPkcs1v15Sign(&rsaPrivateKey, hashAlgo,
292  hashContext.digest, p + 4, &n);
293  }
294 
295  //Check status code
296  if(!error)
297  {
298  //The resulting RSA signature blob is encoded as a string
299  STORE32BE(n, p);
300  //Total number of bytes that have been written
301  *written = sizeof(uint32_t) + n;
302  }
303 
304  //Free previously allocated memory
305  rsaFreePrivateKey(&rsaPrivateKey);
306  }
307  else
308  {
309  //Report an error
311  }
312 
313  //Return status code
314  return error;
315 #else
316  //Not implemented
317  return ERROR_NOT_IMPLEMENTED;
318 #endif
319 }
320 
321 
322 /**
323  * @brief DSA signature generation
324  * @param[in] connection Pointer to the SSH connection
325  * @param[in] publicKeyAlgo Public key algorithm
326  * @param[in] hostKey Pointer to the signer's host key
327  * @param[in] sessionId Session identifier (optional parameter)
328  * @param[in] message Pointer to the message to be signed
329  * @param[out] p Output stream where to write the signature
330  * @param[out] written Total number of bytes that have been written
331  * @return Error code
332  **/
333 
335  const char_t *publicKeyAlgo, const SshHostKey *hostKey,
337  uint8_t *p, size_t *written)
338 {
339 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
340  error_t error;
341  size_t n;
342  SshContext *context;
343  DsaPrivateKey dsaPrivateKey;
344  DsaSignature dsaSignature;
345  Sha1Context sha1Context;
346 
347  //Initialize variable
348  n = 0;
349 
350  //Point to the SSH context
351  context = connection->context;
352 
353  //Initialize DSA private key
354  dsaInitPrivateKey(&dsaPrivateKey);
355  //Initialize DSA signature
356  dsaInitSignature(&dsaSignature);
357 
358  //Initialize hash context
359  sha1Init(&sha1Context);
360 
361  //Valid session identifier?
362  if(sessionId != NULL)
363  {
364  uint8_t temp[4];
365 
366  //Encode the length of the session identifier as a 32-bit big-endian
367  //integer
368  STORE32BE(sessionId->length, temp);
369 
370  //Digest the length field
371  sha1Update(&sha1Context, temp, sizeof(temp));
372  //Digest the session identifier
373  sha1Update(&sha1Context, sessionId->value, sessionId->length);
374  }
375 
376  //Digest the message
377  sha1Update(&sha1Context, message->value, message->length);
378  sha1Final(&sha1Context, NULL);
379 
380  //Import DSA private key
381  error = sshImportDsaPrivateKey(hostKey->privateKey,
382  hostKey->privateKeyLen, hostKey->password, &dsaPrivateKey);
383 
384  //Check status code
385  if(!error)
386  {
387  //Generate DSA signature
388  error = dsaGenerateSignature(context->prngAlgo, context->prngContext,
389  &dsaPrivateKey, sha1Context.digest, SHA1_DIGEST_SIZE, &dsaSignature);
390  }
391 
392  //Check status code
393  if(!error)
394  {
395  //The DSA signature blob contains R followed by S (which are 160-bit
396  //integers)
397  n = mpiGetByteLength(&dsaPrivateKey.params.q);
398 
399  //Encode integer R
400  error = mpiExport(&dsaSignature.r, p + 4, n, MPI_FORMAT_BIG_ENDIAN);
401  }
402 
403  //Check status code
404  if(!error)
405  {
406  //Encode integer S
407  error = mpiExport(&dsaSignature.s, p + n + 4, n, MPI_FORMAT_BIG_ENDIAN);
408  }
409 
410  //Check status code
411  if(!error)
412  {
413  //The resulting DSA signature blob is encoded as a string
414  STORE32BE(2 * n, p);
415  //Total number of bytes that have been written
416  *written = sizeof(uint32_t) + 2 * n;
417  }
418 
419  //Free previously allocated resources
420  dsaFreePrivateKey(&dsaPrivateKey);
421  dsaFreeSignature(&dsaSignature);
422 
423  //Return status code
424  return error;
425 #else
426  //Not implemented
427  return ERROR_NOT_IMPLEMENTED;
428 #endif
429 }
430 
431 
432 /**
433  * @brief ECDSA signature generation
434  * @param[in] connection Pointer to the SSH connection
435  * @param[in] publicKeyAlgo Public key algorithm
436  * @param[in] hostKey Pointer to the signer's host key
437  * @param[in] sessionId Session identifier (optional parameter)
438  * @param[in] message Pointer to the message to be signed
439  * @param[out] p Output stream where to write the signature
440  * @param[out] written Total number of bytes that have been written
441  * @return Error code
442  **/
443 
445  const char_t *publicKeyAlgo, const SshHostKey *hostKey,
447  uint8_t *p, size_t *written)
448 {
449 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
450  error_t error;
451  size_t rLen;
452  size_t sLen;
453  SshContext *context;
454  const HashAlgo *hashAlgo;
455  const EcCurveInfo *curveInfo;
456  HashContext hashContext;
457 
458  //Point to the SSH context
459  context = connection->context;
460 
461 #if (SSH_NISTP256_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
462  //ECDSA with NIST P-256 public key algorithm?
463  if(sshCompareAlgo(publicKeyAlgo, "ecdsa-sha2-nistp256"))
464  {
465  //Select the relevant curve and hash algorithm
466  curveInfo = SECP256R1_CURVE;
467  hashAlgo = SHA256_HASH_ALGO;
468  }
469  else
470 #endif
471 #if (SSH_NISTP384_SUPPORT == ENABLED && SSH_SHA384_SUPPORT == ENABLED)
472  //ECDSA with NIST P-384 public key algorithm?
473  if(sshCompareAlgo(publicKeyAlgo, "ecdsa-sha2-nistp384"))
474  {
475  //Select the relevant curve and hash algorithm
476  curveInfo = SECP384R1_CURVE;
477  hashAlgo = SHA384_HASH_ALGO;
478  }
479  else
480 #endif
481 #if (SSH_NISTP521_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
482  //ECDSA with NIST P-521 public key algorithm?
483  if(sshCompareAlgo(publicKeyAlgo, "ecdsa-sha2-nistp521"))
484  {
485  //Select the relevant curve and hash algorithm
486  curveInfo = SECP521R1_CURVE;
487  hashAlgo = SHA512_HASH_ALGO;
488  }
489  else
490 #endif
491  //Unknown public key algorithm?
492  {
493  //Just for sanity
494  curveInfo = NULL;
495  hashAlgo = NULL;
496  }
497 
498  //Valid parameters?
499  if(curveInfo != NULL && hashAlgo != NULL)
500  {
501  EcDomainParameters ecParams;
502  EcPrivateKey ecPrivateKey;
503  EcdsaSignature ecdsaSignature;
504 
505  //Initialize EC domain parameters
506  ecInitDomainParameters(&ecParams);
507  //Initialize EC private key
508  ecInitPrivateKey(&ecPrivateKey);
509  //Initialize ECDSA signature
510  ecdsaInitSignature(&ecdsaSignature);
511 
512  //Initialize hash context
513  hashAlgo->init(&hashContext);
514 
515  //Valid session identifier?
516  if(sessionId != NULL)
517  {
518  uint8_t temp[4];
519 
520  //Encode the length of the session identifier as a 32-bit big-endian
521  //integer
522  STORE32BE(sessionId->length, temp);
523 
524  //Digest the length field
525  hashAlgo->update(&hashContext, temp, sizeof(temp));
526  //Digest the session identifier
527  hashAlgo->update(&hashContext, sessionId->value, sessionId->length);
528  }
529 
530  //Digest the message
531  hashAlgo->update(&hashContext, message->value, message->length);
532  hashAlgo->final(&hashContext, NULL);
533 
534  //Import EC domain parameters
535  error = ecLoadDomainParameters(&ecParams, curveInfo);
536 
537  //Check status code
538  if(!error)
539  {
540  //Import ECDSA private key
541  error = sshImportEcdsaPrivateKey(hostKey->privateKey,
542  hostKey->privateKeyLen, hostKey->password, &ecPrivateKey);
543  }
544 
545  //Check status code
546  if(!error)
547  {
548  //Generate ECDSA signature
549  error = ecdsaGenerateSignature(context->prngAlgo, context->prngContext,
550  &ecParams, &ecPrivateKey, hashContext.digest, hashAlgo->digestSize,
551  &ecdsaSignature);
552  }
553 
554  //Check status code
555  if(!error)
556  {
557  //Encode integer R
558  error = sshFormatMpint(&ecdsaSignature.r, p + 4, &rLen);
559  }
560 
561  //Check status code
562  if(!error)
563  {
564  //Encode integer S
565  error = sshFormatMpint(&ecdsaSignature.s, p + rLen + 4, &sLen);
566  }
567 
568  //Check status code
569  if(!error)
570  {
571  //The resulting ECDSA signature blob is encoded as a string
572  STORE32BE(rLen + sLen, p);
573  //Total number of bytes that have been written
574  *written = sizeof(uint32_t) + rLen + sLen;
575  }
576 
577  //Free previously allocated resources
578  ecFreeDomainParameters(&ecParams);
579  ecFreePrivateKey(&ecPrivateKey);
580  ecdsaFreeSignature(&ecdsaSignature);
581  }
582  else
583  {
584  //Report an error
586  }
587 
588  //Return status code
589  return error;
590 #else
591  //Not implemented
592  return ERROR_NOT_IMPLEMENTED;
593 #endif
594 }
595 
596 
597 /**
598  * @brief Ed25519 signature generation
599  * @param[in] connection Pointer to the SSH connection
600  * @param[in] publicKeyAlgo Public key algorithm
601  * @param[in] hostKey Pointer to the signer's host key
602  * @param[in] sessionId Session identifier (optional parameter)
603  * @param[in] message Pointer to the message to be signed
604  * @param[out] p Output stream where to write the signature
605  * @param[out] written Total number of bytes that have been written
606  * @return Error code
607  **/
608 
610  const char_t *publicKeyAlgo, const SshHostKey *hostKey,
612  uint8_t *p, size_t *written)
613 {
614 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
615  error_t error;
616  size_t n;
617  EddsaPrivateKey eddsaPrivateKey;
618  EddsaMessageChunk messageChunks[4];
619  uint8_t temp[4];
620  uint8_t d[ED25519_PRIVATE_KEY_LEN];
621 
622  //Initialize EdDSA private key
623  eddsaInitPrivateKey(&eddsaPrivateKey);
624 
625  //Import Ed25519 private key
626  error = sshImportEd25519PrivateKey(hostKey->privateKey,
627  hostKey->privateKeyLen, hostKey->password, &eddsaPrivateKey);
628 
629  //Check status code
630  if(!error)
631  {
632  //Retrieve raw private key
633  error = mpiExport(&eddsaPrivateKey.d, d, ED25519_PRIVATE_KEY_LEN,
635  }
636 
637  //Check status code
638  if(!error)
639  {
640  //Valid session identifier?
641  if(sessionId != NULL)
642  {
643  //Encode the length of the session identifier as a 32-bit big-endian
644  //integer
645  STORE32BE(sessionId->length, temp);
646 
647  //Data to be signed is run through the EdDSA algorithm without
648  //pre-hashing
649  messageChunks[0].buffer = temp;
650  messageChunks[0].length = sizeof(temp);
651  messageChunks[1].buffer = sessionId->value;
652  messageChunks[1].length = sessionId->length;
653  messageChunks[2].buffer = message->value;
654  messageChunks[2].length = message->length;
655  messageChunks[3].buffer = NULL;
656  messageChunks[3].length = 0;
657  }
658  else
659  {
660  //The message fits in a single chunk
661  messageChunks[0].buffer = message->value;
662  messageChunks[0].length = message->length;
663  messageChunks[1].buffer = NULL;
664  messageChunks[1].length = 0;
665  }
666 
667  //Generate Ed25519 signature (PureEdDSA mode)
668  error = ed25519GenerateSignatureEx(d, NULL, messageChunks, NULL, 0, 0,
669  p + 4);
670 
671  //The Ed25519 signature consists of 32 octets
673  }
674 
675  //Check status code
676  if(!error)
677  {
678  //The resulting EdDSA signature is encoded as a string
679  STORE32BE(n, p);
680  //Total number of bytes that have been written
681  *written = sizeof(uint32_t) + n;
682  }
683 
684  //Free previously allocated resources
685  eddsaFreePrivateKey(&eddsaPrivateKey);
686 
687  //Return status code
688  return error;
689 #else
690  //Not implemented
691  return ERROR_NOT_IMPLEMENTED;
692 #endif
693 }
694 
695 
696 /**
697  * @brief Ed448 signature generation
698  * @param[in] connection Pointer to the SSH connection
699  * @param[in] publicKeyAlgo Public key algorithm
700  * @param[in] hostKey Pointer to the signer's host key
701  * @param[in] sessionId Session identifier (optional parameter)
702  * @param[in] message Pointer to the message to be signed
703  * @param[out] p Output stream where to write the signature
704  * @param[out] written Total number of bytes that have been written
705  * @return Error code
706  **/
707 
709  const char_t *publicKeyAlgo, const SshHostKey *hostKey,
711  uint8_t *p, size_t *written)
712 {
713 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
714  error_t error;
715  size_t n;
716  EddsaPrivateKey eddsaPrivateKey;
717  EddsaMessageChunk messageChunks[4];
718  uint8_t temp[4];
719  uint8_t d[ED448_PRIVATE_KEY_LEN];
720 
721  //Initialize EdDSA private key
722  eddsaInitPrivateKey(&eddsaPrivateKey);
723 
724  //Import Ed448 private key
725  error = sshImportEd448PrivateKey(hostKey->privateKey,
726  hostKey->privateKeyLen, hostKey->password, &eddsaPrivateKey);
727 
728  //Check status code
729  if(!error)
730  {
731  //Retrieve raw private key
732  error = mpiExport(&eddsaPrivateKey.d, d, ED448_PRIVATE_KEY_LEN,
734  }
735 
736  //Check status code
737  if(!error)
738  {
739  //Valid session identifier?
740  if(sessionId != NULL)
741  {
742  //Encode the length of the session identifier as a 32-bit big-endian
743  //integer
744  STORE32BE(sessionId->length, temp);
745 
746  //Data to be signed is run through the EdDSA algorithm without
747  //pre-hashing
748  messageChunks[0].buffer = temp;
749  messageChunks[0].length = sizeof(temp);
750  messageChunks[1].buffer = sessionId->value;
751  messageChunks[1].length = sessionId->length;
752  messageChunks[2].buffer = message->value;
753  messageChunks[2].length = message->length;
754  messageChunks[3].buffer = NULL;
755  messageChunks[3].length = 0;
756  }
757  else
758  {
759  //The message fits in a single chunk
760  messageChunks[0].buffer = message->value;
761  messageChunks[0].length = message->length;
762  messageChunks[1].buffer = NULL;
763  messageChunks[1].length = 0;
764  }
765 
766  //Generate Ed448 signature (PureEdDSA mode)
767  error = ed448GenerateSignatureEx(d, NULL, messageChunks, NULL, 0, 0,
768  p + 4);
769 
770  //The Ed448 signature consists of 57 octets
772  }
773 
774  //Check status code
775  if(!error)
776  {
777  //The resulting EdDSA signature is encoded as a string
778  STORE32BE(n, p);
779  //Total number of bytes that have been written
780  *written = sizeof(uint32_t) + n;
781  }
782 
783  //Free previously allocated resources
784  eddsaFreePrivateKey(&eddsaPrivateKey);
785 
786  //Return status code
787  return error;
788 #else
789  //Not implemented
790  return ERROR_NOT_IMPLEMENTED;
791 #endif
792 }
793 
794 
795 /**
796  * @brief Signature verification
797  * @param[in] connection Pointer to the SSH connection
798  * @param[in] publicKeyAlgo Public key algorithm
799  * @param[in] publicKeyBlob Signer's public key
800  * @param[in] sessionId Session identifier (optional parameter)
801  * @param[in] message Message whose signature is to be verified
802  * @param[in] signature Signature to be verified
803  * @return Error code
804  **/
805 
807  const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob,
809  const SshBinaryString *signature)
810 {
811  error_t error;
812  size_t n;
813  const uint8_t *p;
814  SshString keyFormatId;
815  SshString signFormatId;
816  SshBinaryString signatureBlob;
817  const char_t *expectedKeyFormatId;
818  const char_t *expectedSignFormatId;
819 
820  //Point to the first field of the signature
821  p = signature->value;
822  n = signature->length;
823 
824  //Decode signature format identifier
825  error = sshParseString(p, n, &signFormatId);
826  //Any error to report?
827  if(error)
828  return error;
829 
830  //Point to the next field
831  p += sizeof(uint32_t) + signFormatId.length;
832  n -= sizeof(uint32_t) + signFormatId.length;
833 
834  //Decode signature blob
835  error = sshParseBinaryString(p, n, &signatureBlob);
836  //Any error to report?
837  if(error)
838  return error;
839 
840  //Point to the next field
841  p += sizeof(uint32_t) + signatureBlob.length;
842  n -= sizeof(uint32_t) + signatureBlob.length;
843 
844  //Malformed signature?
845  if(n != 0)
846  return ERROR_INVALID_MESSAGE;
847 
848  //Extract key format identifier from public key blob
849  error = sshParseString(publicKeyBlob->value, publicKeyBlob->length,
850  &keyFormatId);
851  //Any error to report?
852  if(error)
853  return error;
854 
855  //Each public key algorithm is associated with a particular key format
856  expectedKeyFormatId = sshGetKeyFormatId(publicKeyAlgo);
857 
858  //Inconsistent key format identifier?
859  if(!sshCompareString(&keyFormatId, expectedKeyFormatId))
861 
862  //Public key/certificate formats that do not explicitly specify a signature
863  //format identifier must use the public key/certificate format identifier
864  //as the signature identifier (refer to RFC 4253, section 6.6)
865  expectedSignFormatId = sshGetSignFormatId(publicKeyAlgo);
866 
867  //Inconsistent signature format identifier?
868  if(!sshCompareString(&signFormatId, expectedSignFormatId))
870 
871 #if (SSH_SIGN_CALLBACK_SUPPORT == ENABLED)
872  //Valid signature verification callback function?
873  if(connection->context->signVerifyCallback != NULL)
874  {
875  //Invoke user-defined callback
876  error = connection->context->signVerifyCallback(connection,
877  publicKeyAlgo, publicKeyBlob, sessionId, message, &signatureBlob);
878  }
879  else
880 #endif
881  {
882  //No callback function registered
884  }
885 
886  //Check status code
888  {
889 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
890  //RSA signature algorithm?
891  if(sshCompareString(&signFormatId, "ssh-rsa") ||
892  sshCompareString(&signFormatId, "rsa-sha2-256") ||
893  sshCompareString(&signFormatId, "rsa-sha2-512"))
894  {
895  //RSA signature verification
896  error = sshVerifyRsaSignature(publicKeyAlgo, publicKeyBlob,
897  sessionId, message, &signatureBlob);
898  }
899  else
900 #endif
901 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
902  //DSA signature algorithm?
903  if(sshCompareString(&signFormatId, "ssh-dss"))
904  {
905  //DSA signature verification
906  error = sshVerifyDsaSignature(publicKeyAlgo, publicKeyBlob,
907  sessionId, message, &signatureBlob);
908  }
909  else
910 #endif
911 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
912  //ECDSA signature algorithm?
913  if(sshCompareString(&signFormatId, "ecdsa-sha2-nistp256") ||
914  sshCompareString(&signFormatId, "ecdsa-sha2-nistp384") ||
915  sshCompareString(&signFormatId, "ecdsa-sha2-nistp521"))
916  {
917  //ECDSA signature verification
918  error = sshVerifyEcdsaSignature(publicKeyAlgo, publicKeyBlob,
919  sessionId, message, &signatureBlob);
920  }
921  else
922 #endif
923 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
924  //Ed22519 signature algorithm?
925  if(sshCompareString(&signFormatId, "ssh-ed25519"))
926  {
927  //Ed25519 signature verification
928  error = sshVerifyEd25519Signature(publicKeyAlgo, publicKeyBlob,
929  sessionId, message, &signatureBlob);
930  }
931  else
932 #endif
933 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
934  //Ed448 signature algorithm?
935  if(sshCompareString(&signFormatId, "ssh-ed448"))
936  {
937  //Ed448 signature verification
938  error = sshVerifyEd448Signature(publicKeyAlgo, publicKeyBlob,
939  sessionId, message, &signatureBlob);
940  }
941  else
942 #endif
943  //Unknown public key type?
944  {
945  //Report an error
947  }
948  }
949 
950  //Return status code
951  return error;
952 }
953 
954 
955 /**
956  * @brief RSA signature verification
957  * @param[in] publicKeyAlgo Public key algorithm
958  * @param[in] publicKeyBlob Signer's public key
959  * @param[in] sessionId Session identifier (optional parameter)
960  * @param[in] message Message whose signature is to be verified
961  * @param[in] signatureBlob Signature to be verified
962  * @return Error code
963  **/
964 
966  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
967  const SshBinaryString *message, const SshBinaryString *signatureBlob)
968 {
969 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
970  error_t error;
971  const HashAlgo *hashAlgo;
972  HashContext hashContext;
973 
974 #if (SSH_SHA1_SUPPORT == ENABLED)
975  //RSA with SHA-1 public key algorithm?
976  if(sshCompareString(publicKeyAlgo, "ssh-rsa") ||
977  sshCompareString(publicKeyAlgo, "ssh-rsa-cert-v01@openssh.com"))
978  {
979  //Select the relevant hash algorithm
980  hashAlgo = SHA1_HASH_ALGO;
981  }
982  else
983 #endif
984 #if (SSH_SHA256_SUPPORT == ENABLED)
985  //RSA with SHA-256 public key algorithm?
986  if(sshCompareString(publicKeyAlgo, "rsa-sha2-256") ||
987  sshCompareString(publicKeyAlgo, "rsa-sha2-256-cert-v01@openssh.com"))
988  {
989  //Select the relevant hash algorithm
990  hashAlgo = SHA256_HASH_ALGO;
991  }
992  else
993 #endif
994 #if (SSH_SHA512_SUPPORT == ENABLED)
995  //RSA with SHA-512 public key algorithm?
996  if(sshCompareString(publicKeyAlgo, "rsa-sha2-512") ||
997  sshCompareString(publicKeyAlgo, "rsa-sha2-512-cert-v01@openssh.com"))
998  {
999  //Select the relevant hash algorithm
1000  hashAlgo = SHA512_HASH_ALGO;
1001  }
1002  else
1003 #endif
1004  //Unknown public key algorithm?
1005  {
1006  //Just for sanity
1007  hashAlgo = NULL;
1008  }
1009 
1010  //Make sure the hash algorithm is supported
1011  if(hashAlgo != NULL)
1012  {
1013  RsaPublicKey rsaPublicKey;
1014 
1015  //Initialize RSA public key
1016  rsaInitPublicKey(&rsaPublicKey);
1017 
1018  //Initialize hash context
1019  hashAlgo->init(&hashContext);
1020 
1021  //Valid session identifier?
1022  if(sessionId != NULL)
1023  {
1024  uint8_t temp[4];
1025 
1026  //Encode the length of the session identifier as a 32-bit big-endian
1027  //integer
1028  STORE32BE(sessionId->length, temp);
1029 
1030  //Digest the length field
1031  hashAlgo->update(&hashContext, temp, sizeof(temp));
1032  //Digest the session identifier
1033  hashAlgo->update(&hashContext, sessionId->value, sessionId->length);
1034  }
1035 
1036  //Digest the message
1037  hashAlgo->update(&hashContext, message->value, message->length);
1038  hashAlgo->final(&hashContext, NULL);
1039 
1040 #if (SSH_CERT_SUPPORT == ENABLED)
1041  //RSA certificate?
1042  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
1043  {
1044  SshCertificate cert;
1045 
1046  //Parse RSA certificate structure
1047  error = sshParseCertificate(publicKeyBlob->value,
1048  publicKeyBlob->length, &cert);
1049 
1050  //Check status
1051  if(!error)
1052  {
1053  //Import RSA public key
1054  error = sshImportRsaCertPublicKey(&cert, &rsaPublicKey);
1055  }
1056  }
1057  else
1058 #endif
1059  //RSA public key?
1060  {
1061  SshRsaHostKey hostKey;
1062 
1063  //Parse RSA host key structure
1064  error = sshParseRsaHostKey(publicKeyBlob->value, publicKeyBlob->length,
1065  &hostKey);
1066 
1067  //Check status code
1068  if(!error)
1069  {
1070  //Import RSA public key
1071  error = sshImportRsaHostKey(&hostKey, &rsaPublicKey);
1072  }
1073  }
1074 
1075  //Check status code
1076  if(!error)
1077  {
1078  //Verify RSA signature
1079  error = rsassaPkcs1v15Verify(&rsaPublicKey, hashAlgo,
1080  hashContext.digest, signatureBlob->value, signatureBlob->length);
1081  }
1082 
1083  //Free previously allocated resources
1084  rsaFreePublicKey(&rsaPublicKey);
1085  }
1086  else
1087  {
1088  //Report an error
1090  }
1091 
1092  //Return status code
1093  return error;
1094 #else
1095  //Not implemented
1096  return ERROR_NOT_IMPLEMENTED;
1097 #endif
1098 }
1099 
1100 
1101 /**
1102  * @brief DSA signature verification
1103  * @param[in] publicKeyAlgo Public key algorithm
1104  * @param[in] publicKeyBlob Signer's public key
1105  * @param[in] sessionId Session identifier (optional parameter)
1106  * @param[in] message Message whose signature is to be verified
1107  * @param[in] signatureBlob Signature to be verified
1108  * @return Error code
1109  **/
1110 
1112  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
1113  const SshBinaryString *message, const SshBinaryString *signatureBlob)
1114 {
1115 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
1116  error_t error;
1117  DsaPublicKey dsaPublicKey;
1118  DsaSignature dsaSignature;
1119  Sha1Context sha1Context;
1120 
1121  //The DSA signature blob contains R followed by S (which are 160-bit
1122  //integers)
1123  if(signatureBlob->length != 40)
1124  return ERROR_INVALID_MESSAGE;
1125 
1126  //Initialize DSA public key
1127  dsaInitPublicKey(&dsaPublicKey);
1128  //Initialize DSA signature
1129  dsaInitSignature(&dsaSignature);
1130 
1131  //Initialize hash context
1132  sha1Init(&sha1Context);
1133 
1134  //Valid session identifier?
1135  if(sessionId != NULL)
1136  {
1137  uint8_t temp[4];
1138 
1139  //Encode the length of the session identifier as a 32-bit big-endian
1140  //integer
1141  STORE32BE(sessionId->length, temp);
1142 
1143  //Digest the length field
1144  sha1Update(&sha1Context, temp, sizeof(temp));
1145  //Digest the session identifier
1146  sha1Update(&sha1Context, sessionId->value, sessionId->length);
1147  }
1148 
1149  //Digest the message
1150  sha1Update(&sha1Context, message->value, message->length);
1151  sha1Final(&sha1Context, NULL);
1152 
1153 #if (SSH_CERT_SUPPORT == ENABLED)
1154  //DSA certificate?
1155  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
1156  {
1157  SshCertificate cert;
1158 
1159  //Parse DSA certificate structure
1160  error = sshParseCertificate(publicKeyBlob->value, publicKeyBlob->length,
1161  &cert);
1162 
1163  //Check status
1164  if(!error)
1165  {
1166  //Import DSA public key
1167  error = sshImportDsaCertPublicKey(&cert, &dsaPublicKey);
1168  }
1169  }
1170  else
1171 #endif
1172  //DSA public key?
1173  {
1174  SshDsaHostKey hostKey;
1175 
1176  //Parse DSA host key structure
1177  error = sshParseDsaHostKey(publicKeyBlob->value, publicKeyBlob->length,
1178  &hostKey);
1179 
1180  //Check status code
1181  if(!error)
1182  {
1183  //Import DSA public key
1184  error = sshImportDsaHostKey(&hostKey, &dsaPublicKey);
1185  }
1186  }
1187 
1188  //Check status code
1189  if(!error)
1190  {
1191  //Import integer R
1192  error = mpiImport(&dsaSignature.r, signatureBlob->value, 20,
1194  }
1195 
1196  //Check status code
1197  if(!error)
1198  {
1199  //Import integer S
1200  error = mpiImport(&dsaSignature.s, signatureBlob->value + 20, 20,
1202  }
1203 
1204  //Check status code
1205  if(!error)
1206  {
1207  //Verify DSA signature
1208  error = dsaVerifySignature(&dsaPublicKey, sha1Context.digest,
1209  SHA1_DIGEST_SIZE, &dsaSignature);
1210  }
1211 
1212  //Free previously allocated resources
1213  dsaFreePublicKey(&dsaPublicKey);
1214  dsaFreeSignature(&dsaSignature);
1215 
1216  //Return status code
1217  return error;
1218 #else
1219  //Not implemented
1220  return ERROR_NOT_IMPLEMENTED;
1221 #endif
1222 }
1223 
1224 
1225 /**
1226  * @brief ECDSA signature verification
1227  * @param[in] publicKeyAlgo Public key algorithm
1228  * @param[in] publicKeyBlob Signer's public key
1229  * @param[in] sessionId Session identifier (optional parameter)
1230  * @param[in] message Message whose signature is to be verified
1231  * @param[in] signatureBlob Signature to be verified
1232  * @return Error code
1233  **/
1234 
1236  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
1237  const SshBinaryString *message, const SshBinaryString *signatureBlob)
1238 {
1239 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1240  error_t error;
1242  const HashAlgo *hashAlgo;
1243  HashContext hashContext;
1244 
1245 #if (SSH_NISTP256_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
1246  //ECDSA with NIST P-256 public key algorithm?
1247  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256") ||
1248  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256-cert-v01@openssh.com"))
1249  {
1250  //Select the relevant hash algorithm
1251  hashAlgo = SHA256_HASH_ALGO;
1252  }
1253  else
1254 #endif
1255 #if (SSH_NISTP384_SUPPORT == ENABLED && SSH_SHA384_SUPPORT == ENABLED)
1256  //ECDSA with NIST P-384 public key algorithm?
1257  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384") ||
1258  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384-cert-v01@openssh.com"))
1259  {
1260  //Select the relevant hash algorithm
1261  hashAlgo = SHA384_HASH_ALGO;
1262  }
1263  else
1264 #endif
1265 #if (SSH_NISTP521_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
1266  //ECDSA with NIST P-521 public key algorithm?
1267  if(sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521") ||
1268  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521-cert-v01@openssh.com"))
1269  {
1270  //Select the relevant hash algorithm
1271  hashAlgo = SHA512_HASH_ALGO;
1272  }
1273  else
1274 #endif
1275  //Unknown public key algorithm?
1276  {
1277  //Just for sanity
1278  hashAlgo = NULL;
1279  }
1280 
1281  //Make sure the hash algorithm is supported
1282  if(hashAlgo != NULL)
1283  {
1284  EcDomainParameters ecParams;
1285  EcPublicKey ecPublicKey;
1286  EcdsaSignature ecdsaSignature;
1287 
1288  //Initialize EC domain parameters
1289  ecInitDomainParameters(&ecParams);
1290  //Initialize EC public key
1291  ecInitPublicKey(&ecPublicKey);
1292  //Initialize ECDSA signature
1293  ecdsaInitSignature(&ecdsaSignature);
1294 
1295  //Initialize hash context
1296  hashAlgo->init(&hashContext);
1297 
1298  //Valid session identifier?
1299  if(sessionId != NULL)
1300  {
1301  uint8_t temp[4];
1302 
1303  //Encode the length of the session identifier as a 32-bit big-endian
1304  //integer
1305  STORE32BE(sessionId->length, temp);
1306 
1307  //Digest the length field
1308  hashAlgo->update(&hashContext, temp, sizeof(temp));
1309  //Digest the session identifier
1310  hashAlgo->update(&hashContext, sessionId->value, sessionId->length);
1311  }
1312 
1313  //Digest the message
1314  hashAlgo->update(&hashContext, message->value, message->length);
1315  hashAlgo->final(&hashContext, NULL);
1316 
1317 #if (SSH_CERT_SUPPORT == ENABLED)
1318  //ECDSA certificate?
1319  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
1320  {
1321  SshCertificate cert;
1322 
1323  //Parse ECDSA certificate structure
1324  error = sshParseCertificate(publicKeyBlob->value,
1325  publicKeyBlob->length, &cert);
1326 
1327  //Check status
1328  if(!error)
1329  {
1330  //Import ECDSA public key
1331  error = sshImportEcdsaCertPublicKey(&cert, &ecParams, &ecPublicKey);
1332  }
1333  }
1334  else
1335 #endif
1336  //ECDSA public key?
1337  {
1338  SshEcdsaHostKey hostKey;
1339 
1340  //Parse ECDSA host key structure
1341  error = sshParseEcdsaHostKey(publicKeyBlob->value, publicKeyBlob->length,
1342  &hostKey);
1343 
1344  //Check status code
1345  if(!error)
1346  {
1347  //Import ECDSA public key
1348  error = sshImportEcdsaHostKey(&hostKey, &ecParams, &ecPublicKey);
1349  }
1350  }
1351 
1352  //Check status code
1353  if(!error)
1354  {
1355  //Parse ECDSA signature structure
1356  error = sshParseEcdsaSignature(signatureBlob->value,
1357  signatureBlob->length, &signature);
1358  }
1359 
1360  //Check status code
1361  if(!error)
1362  {
1363  //Import integer R
1364  error = mpiImport(&ecdsaSignature.r, signature.r.value,
1365  signature.r.length, MPI_FORMAT_BIG_ENDIAN);
1366  }
1367 
1368  //Check status code
1369  if(!error)
1370  {
1371  //Import integer S
1372  error = mpiImport(&ecdsaSignature.s, signature.s.value,
1373  signature.s.length, MPI_FORMAT_BIG_ENDIAN);
1374  }
1375 
1376  //Check status code
1377  if(!error)
1378  {
1379  //Verify ECDSA signature
1380  error = ecdsaVerifySignature(&ecParams, &ecPublicKey,
1381  hashContext.digest, hashAlgo->digestSize, &ecdsaSignature);
1382  }
1383 
1384  //Free previously allocated resources
1385  ecFreeDomainParameters(&ecParams);
1386  ecFreePublicKey(&ecPublicKey);
1387  ecdsaFreeSignature(&ecdsaSignature);
1388  }
1389  else
1390  {
1391  //Report an error
1393  }
1394 
1395  //Return status code
1396  return error;
1397 #else
1398  //Not implemented
1399  return ERROR_NOT_IMPLEMENTED;
1400 #endif
1401 }
1402 
1403 
1404 /**
1405  * @brief Ed25519 signature verification
1406  * @param[in] publicKeyAlgo Public key algorithm
1407  * @param[in] publicKeyBlob Signer's public key
1408  * @param[in] sessionId Session identifier (optional parameter)
1409  * @param[in] message Message whose signature is to be verified
1410  * @param[in] signatureBlob Signature to be verified
1411  * @return Error code
1412  **/
1413 
1415  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
1416  const SshBinaryString *message, const SshBinaryString *signatureBlob)
1417 {
1418 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
1419  error_t error;
1420  const uint8_t *ed25519PublicKey;
1421  EddsaMessageChunk messageChunks[4];
1422  uint8_t temp[4];
1423 
1424  //The Ed25519 signature consists of 32 octets
1425  if(signatureBlob->length != ED25519_SIGNATURE_LEN)
1426  return ERROR_INVALID_SIGNATURE;
1427 
1428 #if (SSH_CERT_SUPPORT == ENABLED)
1429  //Ed22519 certificate?
1430  if(sshIsCertPublicKeyAlgo(publicKeyAlgo))
1431  {
1432  SshCertificate cert;
1433 
1434  //Parse Ed25519 certificate structure
1435  error = sshParseCertificate(publicKeyBlob->value, publicKeyBlob->length,
1436  &cert);
1437 
1438  //Check status
1439  if(!error)
1440  {
1441  //The Ed25519 public key consists of 32 octets
1442  ed25519PublicKey = cert.publicKey.ed25519PublicKey.q.value;
1443  }
1444  }
1445  else
1446 #endif
1447  //Ed25519 public key?
1448  {
1449  SshEddsaHostKey hostKey;
1450 
1451  //Parse Ed25519 host key structure
1452  error = sshParseEd25519HostKey(publicKeyBlob->value,
1453  publicKeyBlob->length, &hostKey);
1454 
1455  //Check status
1456  if(!error)
1457  {
1458  //The Ed25519 public key consists of 32 octets
1459  ed25519PublicKey = hostKey.q.value;
1460  }
1461  }
1462 
1463  //Check status
1464  if(!error)
1465  {
1466  //Valid session identifier?
1467  if(sessionId != NULL)
1468  {
1469  //Encode the length of the session identifier as a 32-bit big-endian
1470  //integer
1471  STORE32BE(sessionId->length, temp);
1472 
1473  //Data to be signed is run through the EdDSA algorithm without
1474  //pre-hashing
1475  messageChunks[0].buffer = temp;
1476  messageChunks[0].length = sizeof(temp);
1477  messageChunks[1].buffer = sessionId->value;
1478  messageChunks[1].length = sessionId->length;
1479  messageChunks[2].buffer = message->value;
1480  messageChunks[2].length = message->length;
1481  messageChunks[3].buffer = NULL;
1482  messageChunks[3].length = 0;
1483  }
1484  else
1485  {
1486  //The message fits in a single chunk
1487  messageChunks[0].buffer = message->value;
1488  messageChunks[0].length = message->length;
1489  messageChunks[1].buffer = NULL;
1490  messageChunks[1].length = 0;
1491  }
1492 
1493  //Verify Ed25519 signature (PureEdDSA mode)
1494  error = ed25519VerifySignatureEx(ed25519PublicKey, messageChunks, NULL,
1495  0, 0, signatureBlob->value);
1496  }
1497 
1498  //Return status code
1499  return error;
1500 #else
1501  //Not implemented
1502  return ERROR_NOT_IMPLEMENTED;
1503 #endif
1504 }
1505 
1506 
1507 /**
1508  * @brief Ed448 signature verification
1509  * @param[in] publicKeyAlgo Public key algorithm
1510  * @param[in] publicKeyBlob Signer's public key
1511  * @param[in] sessionId Session identifier (optional parameter)
1512  * @param[in] message Message whose signature is to be verified
1513  * @param[in] signatureBlob Signature to be verified
1514  * @return Error code
1515  **/
1516 
1518  const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId,
1519  const SshBinaryString *message, const SshBinaryString *signatureBlob)
1520 {
1521 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
1522  error_t error;
1523  SshEddsaHostKey hostKey;
1524  EddsaMessageChunk messageChunks[4];
1525  uint8_t temp[4];
1526 
1527  //The Ed448 signature consists of 57 octets
1528  if(signatureBlob->length != ED448_SIGNATURE_LEN)
1529  return ERROR_INVALID_SIGNATURE;
1530 
1531  //Parse Ed448 host key structure
1532  error = sshParseEd448HostKey(publicKeyBlob->value, publicKeyBlob->length,
1533  &hostKey);
1534 
1535  //Check status
1536  if(!error)
1537  {
1538  //Valid session identifier?
1539  if(sessionId != NULL)
1540  {
1541  //Encode the length of the session identifier as a 32-bit big-endian
1542  //integer
1543  STORE32BE(sessionId->length, temp);
1544 
1545  //Data to be signed is run through the EdDSA algorithm without
1546  //pre-hashing
1547  messageChunks[0].buffer = temp;
1548  messageChunks[0].length = sizeof(temp);
1549  messageChunks[1].buffer = sessionId->value;
1550  messageChunks[1].length = sessionId->length;
1551  messageChunks[2].buffer = message->value;
1552  messageChunks[2].length = message->length;
1553  messageChunks[3].buffer = NULL;
1554  messageChunks[3].length = 0;
1555  }
1556  else
1557  {
1558  //The message fits in a single chunk
1559  messageChunks[0].buffer = message->value;
1560  messageChunks[0].length = message->length;
1561  messageChunks[1].buffer = NULL;
1562  messageChunks[1].length = 0;
1563  }
1564 
1565  //Verify Ed448 signature (PureEdDSA mode)
1566  error = ed448VerifySignatureEx(hostKey.q.value, messageChunks, NULL,
1567  0, 0, signatureBlob->value);
1568  }
1569 
1570  //Return status code
1571  return error;
1572 #else
1573  //Not implemented
1574  return ERROR_NOT_IMPLEMENTED;
1575 #endif
1576 }
1577 
1578 
1579 /**
1580  * @brief Format an ECDSA signature
1581  * @param[in] signature ECDSA signature
1582  * @param[out] p Output stream where to write the ECDSA signature
1583  * @param[out] written Total number of bytes that have been written
1584  * @return Error code
1585  **/
1586 
1588  uint8_t *p, size_t *written)
1589 {
1590 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1591  error_t error;
1592  size_t rLen;
1593  size_t sLen;
1594 
1595  //Encode integer R
1596  error = sshConvertArrayToMpint(signature->r.value, signature->r.length,
1597  p + 4, &rLen);
1598 
1599  //Check status code
1600  if(!error)
1601  {
1602  //Encode integer S
1603  error = sshConvertArrayToMpint(signature->s.value, signature->s.length,
1604  p + rLen + 4, &sLen);
1605  }
1606 
1607  //Check status code
1608  if(!error)
1609  {
1610  //The resulting ECDSA signature blob is encoded as a string
1611  STORE32BE(rLen + sLen, p);
1612  //Total number of bytes that have been written
1613  *written = sizeof(uint32_t) + rLen + sLen;
1614  }
1615 
1616  //Return status code
1617  return error;
1618 #else
1619  //Not implemented
1620  return ERROR_NOT_IMPLEMENTED;
1621 #endif
1622 }
1623 
1624 
1625 /**
1626  * @brief Parse an ECDSA signature
1627  * @param[in] data Pointer to the ECDSA signature structure
1628  * @param[in] length Length of the ECDSA signature structure, in bytes
1629  * @param[out] signature Information resulting from the parsing process
1630  * @return Error code
1631  **/
1632 
1635 {
1636 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1637  error_t error;
1638 
1639  //Decode integer R
1640  error = sshParseBinaryString(data, length, &signature->r);
1641  //Any error to report?
1642  if(error)
1643  return error;
1644 
1645  //Point to the next field
1646  data += sizeof(uint32_t) + signature->r.length;
1647  length -= sizeof(uint32_t) + signature->r.length;
1648 
1649  //Decode integer S
1650  error = sshParseBinaryString(data, length, &signature->s);
1651  //Any error to report?
1652  if(error)
1653  return error;
1654 
1655  //Point to the next field
1656  data += sizeof(uint32_t) + signature->s.length;
1657  length -= sizeof(uint32_t) + signature->s.length;
1658 
1659  //Malformed signature?
1660  if(length != 0)
1661  return ERROR_INVALID_MESSAGE;
1662 
1663  //Successful processing
1664  return NO_ERROR;
1665 #else
1666  //Not implemented
1667  return ERROR_NOT_IMPLEMENTED;
1668 #endif
1669 }
1670 
1671 #endif
Mpi s
Definition: dsa.h:86
uint8_t length
Definition: coap_common.h:193
ECDSA signature.
Definition: ecdsa.h:49
HashAlgoInit init
Definition: crypto.h:947
Generic hash algorithm context.
#define SHA256_HASH_ALGO
Definition: sha256.h:51
error_t sshGenerateEcdsaSignature(SshConnection *connection, const char_t *publicKeyAlgo, const SshHostKey *hostKey, const SshBinaryString *sessionId, const SshBinaryString *message, uint8_t *p, size_t *written)
ECDSA signature generation.
void rsaFreePublicKey(RsaPublicKey *key)
Release an RSA public key.
Definition: rsa.c:118
error_t ed25519GenerateSignatureEx(const uint8_t *privateKey, const uint8_t *publicKey, const EddsaMessageChunk *messageChunks, const void *context, uint8_t contextLen, uint8_t flag, uint8_t *signature)
EdDSA signature generation.
Definition: ed25519.c:262
#define SHA1_HASH_ALGO
Definition: sha1.h:51
#define SECP521R1_CURVE
Definition: ec_curves.h:235
uint8_t data[]
Definition: ethernet.h:220
#define SHA512_HASH_ALGO
Definition: sha512.h:51
error_t sshParseDsaHostKey(const uint8_t *data, size_t length, SshDsaHostKey *hostKey)
Parse a DSA host key structure.
error_t sshGenerateRsaSignature(SshConnection *connection, const char_t *publicKeyAlgo, const SshHostKey *hostKey, const SshBinaryString *sessionId, const SshBinaryString *message, uint8_t *p, size_t *written)
RSA signature generation.
Binary string.
Definition: ssh_types.h:67
const char_t * privateKey
Private key (PEM or OpenSSH format)
Definition: ssh.h:1106
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
void ecInitDomainParameters(EcDomainParameters *params)
Initialize EC domain parameters.
Definition: ec.c:51
DSA host key.
Definition: ssh_key_parse.h:64
error_t ed448GenerateSignatureEx(const uint8_t *privateKey, const uint8_t *publicKey, const EddsaMessageChunk *messageChunks, const void *context, uint8_t contextLen, uint8_t flag, uint8_t *signature)
EdDSA signature generation.
Definition: ed448.c:249
#define SECP384R1_CURVE
Definition: ec_curves.h:234
void eddsaFreePrivateKey(EddsaPrivateKey *key)
Release an EdDSA private key.
Definition: eddsa.c:89
void eddsaInitPrivateKey(EddsaPrivateKey *key)
Initialize an EdDSA private key.
Definition: eddsa.c:73
ECDSA (Elliptic Curve Digital Signature Algorithm)
uint8_t p
Definition: ndp.h:298
Mpi q
Group order.
Definition: dsa.h:51
void dsaFreePrivateKey(DsaPrivateKey *key)
Release a DSA private key.
Definition: dsa.c:150
error_t sshParseEd448HostKey(const uint8_t *data, size_t length, SshEddsaHostKey *hostKey)
Parse an Ed448 host key structure.
#define SECP256R1_CURVE
Definition: ec_curves.h:233
error_t sshVerifyDsaSignature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
DSA signature verification.
size_t digestSize
Definition: crypto.h:943
HashAlgoUpdate update
Definition: crypto.h:948
uint8_t signature
Definition: tls.h:1455
const void * buffer
Definition: eddsa.h:72
error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
Parse a string.
Definition: ssh_misc.c:1141
#define ED448_SIGNATURE_LEN
Definition: ed448.h:44
Mpi r
Definition: dsa.h:85
char_t name[]
error_t sshImportEd25519PrivateKey(const char_t *input, size_t length, const char_t *password, EddsaPrivateKey *privateKey)
Decode an SSH private key file containing an Ed25519 private key.
size_t length
Definition: ssh_types.h:58
#define ED25519_SIGNATURE_LEN
Definition: ed25519.h:44
SSH key parsing.
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
#define osStrlen(s)
Definition: os_port.h:161
error_t sshGenerateEd25519Signature(SshConnection *connection, const char_t *publicKeyAlgo, const SshHostKey *hostKey, const SshBinaryString *sessionId, const SshBinaryString *message, uint8_t *p, size_t *written)
Ed25519 signature generation.
RSA/DSA/ECDSA/EdDSA signature generation and verification.
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 mpiImport(Mpi *r, const uint8_t *data, uint_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:577
EC domain parameters.
Definition: ec.h:76
error_t sshGenerateDsaSignature(SshConnection *connection, const char_t *publicKeyAlgo, const SshHostKey *hostKey, const SshBinaryString *sessionId, const SshBinaryString *message, uint8_t *p, size_t *written)
DSA signature generation.
void ecFreeDomainParameters(EcDomainParameters *params)
Release EC domain parameters.
Definition: ec.c:72
#define ED25519_PRIVATE_KEY_LEN
Definition: ed25519.h:40
void rsaInitPrivateKey(RsaPrivateKey *key)
Initialize an RSA private key.
Definition: rsa.c:131
bool_t sshCompareString(const SshString *string, const char_t *value)
Compare a binary string against the supplied value.
Definition: ssh_misc.c:1575
bool_t sshIsCertPublicKeyAlgo(const SshString *publicKeyAlgo)
Test if the specified public key algorithm is using certificates.
ECDSA signature.
Definition: ssh_signature.h:48
error_t sshImportDsaHostKey(const SshDsaHostKey *hostKey, DsaPublicKey *publicKey)
Import a DSA host key.
char_t password[SSH_MAX_PASSWORD_LEN+1]
Password used to decrypt the private key.
Definition: ssh.h:1108
size_t length
Definition: ssh_types.h:69
void ecdsaFreeSignature(EcdsaSignature *signature)
Release an ECDSA signature.
Definition: ecdsa.c:82
error_t ecLoadDomainParameters(EcDomainParameters *params, const EcCurveInfo *curveInfo)
Load EC domain parameters.
Definition: ec.c:90
error_t sshConvertArrayToMpint(const uint8_t *value, size_t length, uint8_t *p, size_t *written)
Convert a binary string to mpint representation.
Definition: ssh_misc.c:1520
Elliptic curve parameters.
Definition: ec_curves.h:293
const char_t * sshGetKeyFormatId(const SshString *publicKeyAlgo)
Get the key format identifier used by a given public key algorithm.
error_t mpiExport(const Mpi *a, uint8_t *data, uint_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:662
error_t sshVerifyEcdsaSignature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
ECDSA signature verification.
DSA public key.
Definition: dsa.h:61
void sha1Init(Sha1Context *context)
Initialize SHA-1 message digest context.
__weak_func error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const EcDomainParameters *params, const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen, EcdsaSignature *signature)
ECDSA signature generation.
Definition: ecdsa.c:397
#define SshContext
Definition: ssh.h:831
error_t sshVerifyEd25519Signature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
Ed25519 signature verification.
error_t sshImportRsaCertPublicKey(const SshCertificate *cert, RsaPublicKey *publicKey)
Import an RSA public key from a certificate.
@ MPI_FORMAT_LITTLE_ENDIAN
Definition: mpi.h:60
error_t
Error codes.
Definition: error.h:43
void dsaInitSignature(DsaSignature *signature)
Initialize a DSA signature.
Definition: dsa.c:164
void ecInitPublicKey(EcPublicKey *key)
Initialize an EC public key.
Definition: ec.c:153
void rsaFreePrivateKey(RsaPrivateKey *key)
Release an RSA private key.
Definition: rsa.c:153
bool_t sshCompareAlgo(const char_t *name1, const char_t *name2)
Compare algorithm names.
Definition: ssh_misc.c:1642
RSA public key.
Definition: rsa.h:50
void ecdsaInitSignature(EcdsaSignature *signature)
Initialize an ECDSA signature.
Definition: ecdsa.c:69
__weak_func error_t ecdsaVerifySignature(const EcDomainParameters *params, const EcPublicKey *publicKey, const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
ECDSA signature verification.
Definition: ecdsa.c:507
error_t dsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const DsaPrivateKey *key, const uint8_t *digest, size_t digestLen, DsaSignature *signature)
DSA signature generation.
Definition: dsa.c:484
uint8_t digest[MAX_HASH_DIGEST_SIZE]
EdDSA (Edwards-Curve Digital Signature Algorithm)
void dsaInitPrivateKey(DsaPrivateKey *key)
Initialize a DSA private key.
Definition: dsa.c:133
Host key.
Definition: ssh.h:1102
SSH certificate parsing.
error_t sshParseEcdsaHostKey(const uint8_t *data, size_t length, SshEcdsaHostKey *hostKey)
Parse an ECDSA host key structure.
error_t sshImportEcdsaHostKey(const SshEcdsaHostKey *hostKey, EcDomainParameters *params, EcPublicKey *publicKey)
Import a ECDSA host key.
error_t sshParseEd25519HostKey(const uint8_t *data, size_t length, SshEddsaHostKey *hostKey)
Parse an Ed25519 host key structure.
error_t sshImportEd448PrivateKey(const char_t *input, size_t length, const char_t *password, EddsaPrivateKey *privateKey)
Decode an SSH private key file containing an Ed448 private key.
EC private key.
Definition: ec.h:104
DSA private key.
Definition: dsa.h:72
EdDSA host key.
Definition: ssh_key_parse.h:90
void ecFreePrivateKey(EcPrivateKey *key)
Release an EdDSA private key.
Definition: ec.c:192
error_t sshParseEcdsaSignature(const uint8_t *data, size_t length, SshEcdsaSignature *signature)
Parse an ECDSA signature.
size_t length
Definition: eddsa.h:73
String.
Definition: ssh_types.h:56
error_t sshVerifyRsaSignature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
RSA signature verification.
error_t sshGenerateEd448Signature(SshConnection *connection, const char_t *publicKeyAlgo, const SshHostKey *hostKey, const SshBinaryString *sessionId, const SshBinaryString *message, uint8_t *p, size_t *written)
Ed448 signature generation.
error_t ed448VerifySignatureEx(const uint8_t *publicKey, const EddsaMessageChunk *messageChunks, const void *context, uint8_t contextLen, uint8_t flag, const uint8_t *signature)
EdDSA signature verification.
Definition: ed448.c:420
error_t sshImportDsaCertPublicKey(const SshCertificate *cert, DsaPublicKey *publicKey)
Import a DSA public key from a certificate.
error_t sshVerifySignature(SshConnection *connection, const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signature)
Signature verification.
EdDSA private key.
Definition: eddsa.h:59
const uint8_t * value
Definition: ssh_types.h:68
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 sshFormatMpint(const Mpi *value, uint8_t *p, size_t *written)
Format a multiple precision integer.
Definition: ssh_misc.c:1476
HashAlgoFinal final
Definition: crypto.h:949
#define ED448_PRIVATE_KEY_LEN
Definition: ed448.h:40
EC public key.
Definition: ec.h:94
#define SHA384_HASH_ALGO
Definition: sha384.h:47
char char_t
Definition: compiler_port.h:48
error_t dsaVerifySignature(const DsaPublicKey *key, const uint8_t *digest, size_t digestLen, const DsaSignature *signature)
DSA signature verification.
Definition: dsa.c:585
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:814
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
Mpi d
Private key.
Definition: eddsa.h:60
Message chunk descriptor.
Definition: eddsa.h:71
SshCertPublicKey publicKey
uint8_t n
error_t sshFormatEcdsaSignature(const SshEcdsaSignature *signature, uint8_t *p, size_t *written)
Format an ECDSA signature.
RSA private key.
Definition: rsa.h:61
error_t sshGenerateSignature(SshConnection *connection, const char_t *publicKeyAlgo, const SshHostKey *hostKey, const SshBinaryString *sessionId, const SshBinaryString *message, uint8_t *p, size_t *written)
Signature generation.
Definition: ssh_signature.c:63
#define SshConnection
Definition: ssh.h:835
@ ERROR_UNKOWN_KEY
Definition: error.h:293
error_t sshImportEcdsaPrivateKey(const char_t *input, size_t length, const char_t *password, EcPrivateKey *privateKey)
Decode an SSH private key file containing an ECDSA private key.
error_t sshParseCertificate(const uint8_t *data, size_t length, SshCertificate *cert)
Parse SSH certificate.
ECDSA host key.
Definition: ssh_key_parse.h:78
uint8_t sessionId[]
Definition: tls.h:1701
void dsaFreeSignature(DsaSignature *signature)
Release a DSA signature.
Definition: dsa.c:177
error_t sshVerifyEd448Signature(const SshString *publicKeyAlgo, const SshBinaryString *publicKeyBlob, const SshBinaryString *sessionId, const SshBinaryString *message, const SshBinaryString *signatureBlob)
Ed448 signature verification.
void ecInitPrivateKey(EcPrivateKey *key)
Initialize an EC private key.
Definition: ec.c:177
uint8_t message[]
Definition: chap.h:152
SSH certificate import functions.
SSH helper functions.
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:61
RSA host key.
Definition: ssh_key_parse.h:52
SHA-1 algorithm context.
Definition: sha1.h:64
error_t sshImportRsaPrivateKey(const char_t *input, size_t length, const char_t *password, RsaPrivateKey *privateKey)
Decode an SSH private key file containing an RSA private key.
error_t sshImportEcdsaCertPublicKey(const SshCertificate *cert, EcDomainParameters *params, EcPublicKey *publicKey)
Import an ECDSA public key from a certificate.
size_t privateKeyLen
Length of the private key.
Definition: ssh.h:1107
DsaDomainParameters params
DSA domain parameters.
Definition: dsa.h:73
Common interface for hash algorithms.
Definition: crypto.h:937
error_t rsassaPkcs1v15Sign(const RsaPrivateKey *key, const HashAlgo *hash, const uint8_t *digest, uint8_t *signature, size_t *signatureLen)
RSASSA-PKCS1-v1_5 signature generation operation.
Definition: rsa.c:681
error_t sshParseBinaryString(const uint8_t *p, size_t length, SshBinaryString *string)
Parse a binary string.
Definition: ssh_misc.c:1178
DSA signature.
Definition: dsa.h:84
error_t sshFormatString(const char_t *value, uint8_t *p, size_t *written)
Format a string.
Definition: ssh_misc.c:1373
error_t ed25519VerifySignatureEx(const uint8_t *publicKey, const EddsaMessageChunk *messageChunks, const void *context, uint8_t contextLen, uint8_t flag, const uint8_t *signature)
EdDSA signature verification.
Definition: ed25519.c:445
@ ERROR_UNSUPPORTED_SIGNATURE_ALGO
Definition: error.h:132
error_t sshImportRsaHostKey(const SshRsaHostKey *hostKey, RsaPublicKey *publicKey)
Import an RSA host key.
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:226
void dsaFreePublicKey(DsaPublicKey *key)
Release a DSA public key.
Definition: dsa.c:119
error_t sshImportDsaPrivateKey(const char_t *input, size_t length, const char_t *password, DsaPrivateKey *privateKey)
Decode an SSH private key file containing a DSA private key.
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
uint8_t digest[20]
Definition: sha1.h:68
void dsaInitPublicKey(DsaPublicKey *key)
Initialize a DSA public key.
Definition: dsa.c:105
SSH certificate (OpenSSH format)
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void rsaInitPublicKey(RsaPublicKey *key)
Initialize an RSA public key.
Definition: rsa.c:105
void ecFreePublicKey(EcPublicKey *key)
Release an EC public key.
Definition: ec.c:165
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:156
const char_t * sshGetSignFormatId(const SshString *publicKeyAlgo)
Get the signature format identifier used by a given public key algorithm.
SshEd25519CertPublicKey ed25519PublicKey