148148 algorithms off.
149149 WOLFSSH_KEY_QUANTITY_REQ
150150 Number of keys required to be in an OpenSSH-style key wrapper.
151+ WOLFSSH_NO_CURVE25519_SHA256
152+ Set when Curve25519 or SHA2-256 are disabled in wolfSSL. Set to disable use
153+ of Curve25519 key exchange.
151154*/
152155
153156static const char sshProtoIdStr [] = "SSH-2.0-wolfSSHv"
@@ -571,6 +574,9 @@ static const char cannedKexAlgoNames[] =
571574#if !defined (WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 )
572575 "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org,"
573576#endif
577+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
578+ "curve25519-sha256,"
579+ #endif
574580#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521 )
575581 "ecdh-sha2-nistp521,"
576582#endif
@@ -2148,6 +2154,10 @@ static const NameIdPair NameIdMap[] = {
21482154 /* We use kyber-512 here to achieve interop with OQS's fork. */
21492155 { ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256 , TYPE_KEX ,
21502156 "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org" },
2157+ #endif
2158+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
2159+ /* See RFC 8731 */
2160+ { ID_CURVE25519_SHA256 , TYPE_KEX , "curve25519-sha256" },
21512161#endif
21522162 { ID_EXTINFO_S , TYPE_OTHER , "ext-info-s" },
21532163 { ID_EXTINFO_C , TYPE_OTHER , "ext-info-c" },
@@ -3374,6 +3384,10 @@ static INLINE enum wc_HashType HashForId(byte id)
33743384 case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256 :
33753385 return WC_HASH_TYPE_SHA256 ;
33763386#endif
3387+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
3388+ case ID_CURVE25519_SHA256 :
3389+ return WC_HASH_TYPE_SHA256 ;
3390+ #endif
33773391#ifndef WOLFSSH_NO_RSA_SHA2_256
33783392 case ID_RSA_SHA2_256 :
33793393 return WC_HASH_TYPE_SHA256 ;
@@ -3439,6 +3453,10 @@ static INLINE int wcPrimeForId(byte id)
34393453 case ID_ECDSA_SHA2_NISTP384 :
34403454 return ECC_SECP384R1 ;
34413455#endif
3456+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
3457+ case ID_CURVE25519_SHA256 :
3458+ return ECC_X25519 ;
3459+ #endif
34423460#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521
34433461 case ID_ECDH_SHA2_NISTP521 :
34443462 return ECC_SECP521R1 ;
@@ -4668,6 +4686,9 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
46684686 if (!ssh -> handshake -> useEcc
46694687#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
46704688 && !ssh -> handshake -> useEccKyber
4689+ #endif
4690+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
4691+ && !ssh -> handshake -> useCurve25519
46714692#endif
46724693 ) {
46734694#ifndef WOLFSSH_NO_DH
@@ -4712,6 +4733,37 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
47124733 ret = WS_INVALID_ALGO_ID ;
47134734#endif
47144735 }
4736+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
4737+ else if (ssh -> handshake -> useCurve25519 ) {
4738+ curve25519_key pub ;
4739+ ret = wc_curve25519_init (& pub );
4740+
4741+ if (ret == 0 )
4742+ ret = wc_curve25519_check_public (f , fSz ,
4743+ EC25519_LITTLE_ENDIAN );
4744+
4745+ if (ret == 0 ) {
4746+ ret = wc_curve25519_import_public_ex (f , fSz , & pub ,
4747+ EC25519_LITTLE_ENDIAN );
4748+ }
4749+
4750+ if (ret == 0 ) {
4751+ PRIVATE_KEY_UNLOCK ();
4752+ ret = wc_curve25519_shared_secret_ex (
4753+ & ssh -> handshake -> privKey .curve25519 , & pub ,
4754+ ssh -> k , & ssh -> kSz , EC25519_LITTLE_ENDIAN );
4755+ PRIVATE_KEY_LOCK ();
4756+ }
4757+
4758+ wc_curve25519_free (& pub );
4759+ wc_curve25519_free (& ssh -> handshake -> privKey .curve25519 );
4760+
4761+ if (ret != 0 ) {
4762+ WLOG (WS_LOG_ERROR ,
4763+ "Gen curve25519 shared secret failed, %d" , ret );
4764+ }
4765+ }
4766+ #endif /* !WOLFSSH_NO_CURVE25519_SHA256 */
47154767#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
47164768 else if (ssh -> handshake -> useEccKyber ) {
47174769 /* This is a a hybrid of ECDHE and a post-quantum KEM. In this
@@ -4954,8 +5006,8 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
49545006
49555007 if (ret == WS_SUCCESS ) {
49565008 int useKeyPadding = 1 ;
4957- #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
4958- useKeyPadding = !ssh -> handshake -> useEccKyber ;
5009+ #if !defined( WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 )
5010+ doKeyPadding = !ssh -> handshake -> useEccKyber ;
49595011#endif
49605012 ret = GenerateKeys (ssh , hashId , useKeyPadding );
49615013 }
@@ -9775,6 +9827,9 @@ int SendKexDhReply(WOLFSSH* ssh)
97759827 byte useEccKyber = 0 ;
97769828 byte sharedSecretHashSz = 0 ;
97779829 byte * sharedSecretHash = NULL ;
9830+ #endif
9831+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
9832+ byte useCurve25519 = 0 ;
97789833#endif
97799834 byte fPad = 0 ;
97809835 byte kPad = 0 ;
@@ -9858,6 +9913,12 @@ int SendKexDhReply(WOLFSSH* ssh)
98589913 msgId = MSGID_KEXDH_REPLY ;
98599914 break ;
98609915#endif
9916+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
9917+ case ID_CURVE25519_SHA256 :
9918+ useCurve25519 = 1 ;
9919+ msgId = MSGID_KEXDH_REPLY ;
9920+ break ;
9921+ #endif
98619922#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
98629923 case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256 :
98639924 useEccKyber = 1 ; /* Only support level 1 for now. */
@@ -9901,6 +9962,9 @@ int SendKexDhReply(WOLFSSH* ssh)
99019962 if (!useEcc
99029963#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
99039964 && !useEccKyber
9965+ #endif
9966+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
9967+ && !useCurve25519
99049968#endif
99059969 ) {
99069970#ifndef WOLFSSH_NO_DH
@@ -10016,6 +10080,62 @@ int SendKexDhReply(WOLFSSH* ssh)
1001610080 #endif
1001710081#endif /* !defined(WOLFSSH_NO_ECDH) */
1001810082 }
10083+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
10084+ if (useCurve25519 ) {
10085+ #ifdef WOLFSSH_SMALL_STACK
10086+ curve25519_key * pubKey = NULL , * privKey = NULL ;
10087+ pubKey = (curve25519_key * )WMALLOC (sizeof (curve25519_key ),
10088+ heap , DYNTYPE_PUBKEY );
10089+ privKey = (curve25519_key * )WMALLOC (sizeof (curve25519_key ),
10090+ heap , DYNTYPE_PRIVKEY );
10091+ if (pubKey == NULL || privKey == NULL ) {
10092+ ret = WS_MEMORY_E ;
10093+ }
10094+ #else
10095+ curve25519_key pubKey [1 ], privKey [1 ];
10096+ #endif
10097+
10098+ if (ret == 0 )
10099+ ret = wc_curve25519_init_ex (pubKey , heap ,
10100+ INVALID_DEVID );
10101+ if (ret == 0 )
10102+ ret = wc_curve25519_init_ex (privKey , heap ,
10103+ INVALID_DEVID );
10104+ if (ret == 0 )
10105+ ret = wc_curve25519_check_public (ssh -> handshake -> e ,
10106+ ssh -> handshake -> eSz , EC25519_LITTLE_ENDIAN );
10107+ if (ret == 0 )
10108+ ret = wc_curve25519_import_public_ex (
10109+ ssh -> handshake -> e , ssh -> handshake -> eSz ,
10110+ pubKey , EC25519_LITTLE_ENDIAN );
10111+
10112+ if (ret == 0 )
10113+ ret = wc_curve25519_make_key (ssh -> rng ,
10114+ CURVE25519_KEYSIZE , privKey );
10115+
10116+ if (ret == 0 ) {
10117+ PRIVATE_KEY_UNLOCK ();
10118+ ret = wc_curve25519_export_public_ex (privKey ,
10119+ f_ptr , & fSz , EC25519_LITTLE_ENDIAN );
10120+ PRIVATE_KEY_LOCK ();
10121+ }
10122+
10123+ if (ret == 0 ) {
10124+ PRIVATE_KEY_UNLOCK ();
10125+ ret = wc_curve25519_shared_secret_ex (privKey , pubKey ,
10126+ ssh -> k , & ssh -> kSz , EC25519_LITTLE_ENDIAN );
10127+ PRIVATE_KEY_LOCK ();
10128+ }
10129+ wc_curve25519_free (privKey );
10130+ wc_curve25519_free (pubKey );
10131+ #ifdef WOLFSSH_SMALL_STACK
10132+ WFREE (pubKey , heap , DYNTYPE_PUBKEY );
10133+ WFREE (privKey , heap , DYNTYPE_PRIVKEY );
10134+ pubKey = NULL ;
10135+ privKey = NULL ;
10136+ #endif
10137+ }
10138+ #endif /* ! WOLFSSH_NO_CURVE25519_SHA256 */
1001910139#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
1002010140 else if (useEccKyber ) {
1002110141 /* This is a hybrid KEM. In this case, I need to generate my ECC
@@ -10163,6 +10283,9 @@ int SendKexDhReply(WOLFSSH* ssh)
1016310283 if (ret == 0
1016410284#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
1016510285 && !useEccKyber
10286+ #endif
10287+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
10288+ && !useCurve25519
1016610289#endif
1016710290 ) {
1016810291 ret = CreateMpint (f_ptr , & fSz , & fPad );
@@ -10380,8 +10503,8 @@ int SendKexDhReply(WOLFSSH* ssh)
1038010503
1038110504 if (ret == WS_SUCCESS ) {
1038210505 int doKeyPadding = 1 ;
10383- #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
10384- doKeyPadding = !useEccKyber ;
10506+ #if !defined( WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 )
10507+ doKeyPadding = !ssh -> handshake -> useEccKyber ;
1038510508#endif
1038610509 ret = GenerateKeys (ssh , hashId , doKeyPadding );
1038710510 }
@@ -10795,6 +10918,12 @@ int SendKexDhInit(WOLFSSH* ssh)
1079510918 msgId = MSGID_KEXECDH_INIT ;
1079610919 break ;
1079710920#endif
10921+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
10922+ case ID_CURVE25519_SHA256 :
10923+ ssh -> handshake -> useCurve25519 = 1 ;
10924+ msgId = MSGID_KEXECDH_INIT ;
10925+ break ;
10926+ #endif
1079810927#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
1079910928 case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256 :
1080010929 /* Only support level 1 for now. */
@@ -10813,6 +10942,9 @@ int SendKexDhInit(WOLFSSH* ssh)
1081310942#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
1081410943 && !ssh -> handshake -> useEccKyber
1081510944#endif
10945+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
10946+ && !ssh -> handshake -> useCurve25519
10947+ #endif
1081610948) {
1081710949#ifndef WOLFSSH_NO_DH
1081810950 DhKey * privKey = & ssh -> handshake -> privKey .dh ;
@@ -10828,6 +10960,23 @@ int SendKexDhInit(WOLFSSH* ssh)
1082810960 e , & eSz );
1082910961#endif
1083010962 }
10963+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
10964+ else if (ssh -> handshake -> useCurve25519 ) {
10965+ curve25519_key * privKey = & ssh -> handshake -> privKey .curve25519 ;
10966+ if (ret == 0 )
10967+ ret = wc_curve25519_init_ex (privKey , ssh -> ctx -> heap ,
10968+ INVALID_DEVID );
10969+ if (ret == 0 )
10970+ ret = wc_curve25519_make_key (ssh -> rng , CURVE25519_KEYSIZE ,
10971+ privKey );
10972+ if (ret == 0 ) {
10973+ PRIVATE_KEY_UNLOCK ();
10974+ ret = wc_curve25519_export_public_ex (privKey , e , & eSz ,
10975+ EC25519_LITTLE_ENDIAN );
10976+ PRIVATE_KEY_LOCK ();
10977+ }
10978+ }
10979+ #endif /* ! WOLFSSH_NO_CURVE25519_SHA256 */
1083110980 else if (ssh -> handshake -> useEcc
1083210981#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
1083310982 || ssh -> handshake -> useEccKyber
@@ -10899,6 +11048,10 @@ int SendKexDhInit(WOLFSSH* ssh)
1089911048#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256
1090011049 && !ssh -> handshake -> useEccKyber
1090111050#endif
11051+ #ifndef WOLFSSH_NO_CURVE25519_SHA256
11052+ && !ssh -> handshake -> useCurve25519
11053+ #endif
11054+
1090211055 ) {
1090311056 ret = CreateMpint (e , & eSz , & ePad );
1090411057 }
0 commit comments