diff options
author | René Korthaus <[email protected]> | 2017-10-17 16:22:07 +0200 |
---|---|---|
committer | René Korthaus <[email protected]> | 2017-10-17 16:49:57 +0200 |
commit | 824b2e56ca886585cc2dfd363bb1913c6d416904 (patch) | |
tree | 0de3aea53c9488bc1a1f90c0361d79c44a6f6f9b /src | |
parent | f01f37d142ef230b03ca6af46f1e1a0615e4879a (diff) |
Add supported groups TLS extension (RFC 7919)
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/pubkey/dl_group/dl_named.cpp | 146 | ||||
-rw-r--r-- | src/lib/tls/msg_client_hello.cpp | 16 | ||||
-rw-r--r-- | src/lib/tls/msg_client_kex.cpp | 29 | ||||
-rw-r--r-- | src/lib/tls/msg_server_kex.cpp | 5 | ||||
-rw-r--r-- | src/lib/tls/tls_extensions.cpp | 81 | ||||
-rw-r--r-- | src/lib/tls/tls_extensions.h | 20 | ||||
-rw-r--r-- | src/lib/tls/tls_messages.h | 2 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.cpp | 51 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.h | 18 | ||||
-rw-r--r-- | src/lib/tls/tls_server.cpp | 7 | ||||
-rw-r--r-- | src/lib/tls/tls_text_policy.cpp | 5 | ||||
-rw-r--r-- | src/tests/data/tls-policy/bsi.txt | 1 | ||||
-rw-r--r-- | src/tests/data/tls-policy/suiteb.txt | 1 | ||||
-rw-r--r-- | src/tests/data/tls/client_hello.vec | 8 | ||||
-rw-r--r-- | src/tests/test_dl_group.cpp | 6 | ||||
-rw-r--r-- | src/tests/unit_tls.cpp | 11 |
16 files changed, 372 insertions, 35 deletions
diff --git a/src/lib/pubkey/dl_group/dl_named.cpp b/src/lib/pubkey/dl_group/dl_named.cpp index 4df9732be..fc5cf4fd2 100644 --- a/src/lib/pubkey/dl_group/dl_named.cpp +++ b/src/lib/pubkey/dl_group/dl_named.cpp @@ -354,6 +354,152 @@ std::string DL_Group::PEM_for_named_group(const std::string& name) "eMFVkc39EVZP+I/zi3IdQjkv2kcyEtz9jS2IqXagCv/m//tDCjWeZMorNRyiQSOU" "-----END DSA PARAMETERS-----"; + if(name == "ffdhe/ietf/2048") + return + "-----BEGIN DSA PARAMETERS-----" + "MIICDAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz" + "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a" + "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7" + "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi" + "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD" + "ssbzSibBsu/6iGtCOGEoXJf//////////wKCAQB//////////9b8KixRXaVNV+4r" + "EBOennjsXOLB5xabStTwmyCKMhn95knO5xJNn3y+l/GxsYY67HtA2QFXYjC9ae+P" + "aur+srCSGfqPr4M3aEKxsqqe9o152quJrz+r5JrMJ4Y4cHNFu/FTRO159/Q5Dvis" + "UJtW85qYVmUnpB08vV4FWMFZkn2w6IRUpdlkcf3ctW1bsGv6NA6noVHvHKb6Vyt2" + "87G5XYyFg9PkdwU2uE8BfnDm+/F2YBoCZpQaF7DIuX9OdMLB/8cniRl3eUDB4f8d" + "jaY31rmd2v5eF2EQAuLHeMG+i0HZY3mlE2DZd/1ENaEcMJQuS///////////AgEC" + "-----END DSA PARAMETERS-----"; + + if(name == "ffdhe/ietf/3072") + return + "-----BEGIN DSA PARAMETERS-----" + "MIIDDAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz" + "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a" + "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7" + "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi" + "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD" + "ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3" + "7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32" + "nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu" + "N///////////AoIBgH//////////1vwqLFFdpU1X7isQE56eeOxc4sHnFptK1PCb" + "IIoyGf3mSc7nEk2ffL6X8bGxhjrse0DZAVdiML1p749q6v6ysJIZ+o+vgzdoQrGy" + "qp72jXnaq4mvP6vkmswnhjhwc0W78VNE7Xn39DkO+KxQm1bzmphWZSekHTy9XgVY" + "wVmSfbDohFSl2WRx/dy1bVuwa/o0DqehUe8cpvpXK3bzsbldjIWD0+R3BTa4TwF+" + "cOb78XZgGgJmlBoXsMi5f050wsH/xyeJGXd5QMHh/x2NpjfWuZ3a/l4XYRAC4sd4" + "wb6LQdljeaUTYNl3/UQ1oRwwj+fubxqtnbKMga3eGnpvfM4BHDDaN+Trc2SDvWyO" + "k0j7+/csxlh9YMNsjld/CYTCick4WgmGSd4hvKJ6fqIpcWum6bJ5cQ84+qX/rldB" + "Vc5O+090NpXikRsdBtXikMvNhvVtDt/NIWriJCcFXmg1/Snu954NkHcf6s6+EvIO" + "lbNjFxv//////////wIBAg==" + "-----END DSA PARAMETERS-----"; + + if(name == "ffdhe/ietf/4096") + return + "-----BEGIN DSA PARAMETERS-----" + "MIIDDAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz" + "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a" + "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7" + "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi" + "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD" + "ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3" + "7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32" + "nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu" + "N///////////AoIBgH//////////1vwqLFFdpU1X7isQE56eeOxc4sHnFptK1PCb" + "IIoyGf3mSc7nEk2ffL6X8bGxhjrse0DZAVdiML1p749q6v6ysJIZ+o+vgzdoQrGy" + "qp72jXnaq4mvP6vkmswnhjhwc0W78VNE7Xn39DkO+KxQm1bzmphWZSekHTy9XgVY" + "wVmSfbDohFSl2WRx/dy1bVuwa/o0DqehUe8cpvpXK3bzsbldjIWD0+R3BTa4TwF+" + "cOb78XZgGgJmlBoXsMi5f050wsH/xyeJGXd5QMHh/x2NpjfWuZ3a/l4XYRAC4sd4" + "wb6LQdljeaUTYNl3/UQ1oRwwj+fubxqtnbKMga3eGnpvfM4BHDDaN+Trc2SDvWyO" + "k0j7+/csxlh9YMNsjld/CYTCick4WgmGSd4hvKJ6fqIpcWum6bJ5cQ84+qX/rldB" + "Vc5O+090NpXikRsdBtXikMvNhvVtDt/NIWriJCcFXmg1/Snu954NkHcf6s6+EvIO" + "lbNjFxv//////////wIBAg==" + "-----END DSA PARAMETERS-----"; + + if(name == "ffdhe/ietf/6144") + return + "-----BEGIN DSA PARAMETERS-----" + "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" + "TmhyBzL//////////wIBAg==" + "-----END DSA PARAMETERS-----"; + + if(name == "ffdhe/ietf/8192") + return + "-----BEGIN DSA PARAMETERS-----" + "MIIIDAKCBAEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz" + "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a" + "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7" + "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi" + "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD" + "ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3" + "7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32" + "nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e" + "8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx" + "iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K" + "zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eDdkCC/1ktkUDbHpOZ30sOFMq" + "OiO6RELK9T6mO7RUMpt2JMiRe91kscD9TLOOjDNMcBw6za0GV/zP7HGbH1w+TkYE" + "HziBR/tM/bR3pSRx96mpaRC4VTIu22NA2KAO8JI1BRHjCr7B//njom5/sp+MGDAj" + "w1h+ONoAd9m0dj5OS5Syu8GUxmUed8r5ku6qwCMqKBv2s6c5wSJhFoIK6NtYR6Z8" + "vvnJCRtGLVOM1ysDdGrnf15iKSwxFWKoRlBdyC24VDOK5J9SNclbkReMzy3Vys70" + "A+ydGBDGJysEWztx+dxrgNY/3UqOmtseaWKmlSbUMWHBpB1XDXk42tSkDjKcz/Rq" + "qjatAEz2AMg4HkJaMdlRrmT9sj/OyVCdQ2h/62nt0cxeC4zDvfZLEO+GtjFCo6uI" + "KVVbL3R8kyZlyywPHMAb1wIpOIg50q8F5FRQSseLdYKCKEbAujXDX1xZFgzARv2C" + "UVQfxoychrAiu3CZh2pGDnRRqKkxCXA/7hwhfmw4JuUsUappHg5CPPyZ6eMWUMEh" + "e2JIFs2tmpX51bgBlIjZwKCh/jB1pXfiMYP4HUo/L6RXHvyM4LqKT+i2hV3+crCm" + "bt7S+6v75Yow+vq+HF1xqH4vdB74wf6G/qa7/eUwZ38Nl9EdSfeoRD0IIuUGqfRh" + "TgEeKpSDj/iM1oyLt8XGQkz//////////wKCBAB//////////9b8KixRXaVNV+4r" + "EBOennjsXOLB5xabStTwmyCKMhn95knO5xJNn3y+l/GxsYY67HtA2QFXYjC9ae+P" + "aur+srCSGfqPr4M3aEKxsqqe9o152quJrz+r5JrMJ4Y4cHNFu/FTRO159/Q5Dvis" + "UJtW85qYVmUnpB08vV4FWMFZkn2w6IRUpdlkcf3ctW1bsGv6NA6noVHvHKb6Vyt2" + "87G5XYyFg9PkdwU2uE8BfnDm+/F2YBoCZpQaF7DIuX9OdMLB/8cniRl3eUDB4f8d" + "jaY31rmd2v5eF2EQAuLHeMG+i0HZY3mlE2DZd/1ENaEcMI/n7m8arZ2yjIGt3hp6" + "b3zOARww2jfk63Nkg71sjpNI+/v3LMZYfWDDbI5XfwmEwonJOFoJhkneIbyien6i" + "KXFrpumyeXEPOPql/65XQVXOTvtPdDaV4pEbHQbV4pDLzYb1bQ7fzSFq4iQnBV5o" + "Nf0p7veeDZB3H+rOvhLyDpWzTw94tzepYYsm+n28mHTycsQr21Y+r6FrT7aMO7Hn" + "jqqBoAJD+q3SvxjmPTia5EN32hjFdrUPAJbPNBlUg7AFSMCYYjbjvHy41oAcBJTM" + "0Znlxb0NDtyeuKAAHhUnZ1T8xoVmBUFI5udkvufHZNqtP8RSNaba1Cj6IMFw40UA" + "Py8G7IEF/rJbIoG2PSczvpYcKZUdEd0iIWV6n1Md2ioZTbsSZEi97rJY4H6mWcdG" + "GaY4Dh1m1oMr/mf2OM2Prh8nIwIPnECj/aZ+2jvSkjj71NS0iFwqmRdtsaBsUAd4" + "SRqCiPGFX2D//PHRNz/ZT8YMGBHhrD8cbQA77No7Hyclylld4MpjMo875XzJd1Vg" + "EZUUDftZ05zgkTCLQQV0bawj0z5ffOSEjaMWqcZrlYG6NXO/rzEUlhiKsVQjKC7k" + "FtwqGcVyT6ka5K3Ii8ZnlurlZ3oB9k6MCGMTlYItnbj87jXAax/upUdNbY80sVNK" + "k2oYsODSDquGvJxtalIHGU5n+jVVG1aAJnsAZBwPIS0Y7KjXMn7ZH+dkqE6htD/1" + "tPbo5i8FxmHe+yWId8NbGKFR1cQUqq2Xuj5JkzLllgeOYA3rgRScRBzpV4LyKigl" + "Y8W6wUEUI2BdGuGvriyLBmAjfsEoqg/jRk5DWBFduEzDtSMHOijUVJiEuB/3DhC/" + "NhwTcpYo1TSPByEefkz08YsoYJC9sSQLZtbNSvzq3ADKRGzgUFD/GDrSu/EYwfwO" + "pR+X0iuPfkZwXUUn9FtCrv85WFM3b2l91f3yxRh9fV8OLrjUPxe6D3xg/0N/U13+" + "8pgzv4bL6I6k+9QiHoQRcoNU+jCnAI8VSkHH/EZrRkXb4uMhJn//////////AgEC" + "-----END DSA PARAMETERS-----"; + return ""; } diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp index bb7d84df8..e804a0cf0 100644 --- a/src/lib/tls/msg_client_hello.cpp +++ b/src/lib/tls/msg_client_hello.cpp @@ -121,9 +121,10 @@ Client_Hello::Client_Hello(Handshake_IO& io, } #endif - m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves())); + Supported_Groups* supported_groups = new Supported_Groups(policy.allowed_groups()); + m_extensions.add(supported_groups); - if(!policy.allowed_ecc_curves().empty()) + if(!supported_groups->curves().empty()) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } @@ -324,8 +325,15 @@ std::set<std::string> Client_Hello::supported_sig_algos() const std::vector<std::string> Client_Hello::supported_ecc_curves() const { - if(Supported_Elliptic_Curves* ecc = m_extensions.get<Supported_Elliptic_Curves>()) - return ecc->curves(); + if(Supported_Groups* groups = m_extensions.get<Supported_Groups>()) + return groups->curves(); + return std::vector<std::string>(); + } + +std::vector<std::string> Client_Hello::supported_dh_groups() const + { + if(Supported_Groups* groups = m_extensions.get<Supported_Groups>()) + return groups->dh_groups(); return std::vector<std::string>(); } diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp index 3291b6eb5..1c3950a03 100644 --- a/src/lib/tls/msg_client_kex.cpp +++ b/src/lib/tls/msg_client_kex.cpp @@ -101,6 +101,35 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, throw Decoding_Error("Bad params size for DH key exchange"); /* + * If we offer ffdhe groups in the client hello, + * p and g must match one of these groups. + */ + std::vector<std::string> allowed_groups = policy.allowed_groups(); + bool server_sent_requested_group = false; + + if(!allowed_groups.empty()) + { + for(const auto& allowed_group : allowed_groups) + { + if(Supported_Groups::is_dh_group(allowed_group)) + { + DL_Group client_group(allowed_group); + if(client_group.get_p() == p && client_group.get_g() == g) + { + server_sent_requested_group = true; + break; + } + } + } + } + + if(!server_sent_requested_group) + { + throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, + "Server sent unexpected DH key for DHE exchange"); + } + + /* * A basic check for key validity. As we do not know q here we * cannot check that Y is in the right subgroup. However since * our key is ephemeral there does not seem to be any diff --git a/src/lib/tls/msg_server_kex.cpp b/src/lib/tls/msg_server_kex.cpp index 97ac4ac8f..0765e1bdc 100644 --- a/src/lib/tls/msg_server_kex.cpp +++ b/src/lib/tls/msg_server_kex.cpp @@ -56,7 +56,10 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, if(kex_algo == "DH" || kex_algo == "DHE_PSK") { - std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, DL_Group(policy.dh_group()))); + const std::vector<std::string>& dh_groups = + state.client_hello()->supported_dh_groups(); + + std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, DL_Group(policy.choose_dh_group(dh_groups)))); append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp index 317d96b8d..8f13b2c6d 100644 --- a/src/lib/tls/tls_extensions.cpp +++ b/src/lib/tls/tls_extensions.cpp @@ -275,7 +275,23 @@ std::vector<uint8_t> Application_Layer_Protocol_Notification::serialize() const return buf; } -std::string Supported_Elliptic_Curves::curve_id_to_name(uint16_t id) +Supported_Groups::Supported_Groups(const std::vector<std::string>& groups) : + m_groups(groups) + { + for(const auto& group : m_groups) + { + if(is_dh_group(group)) + { + m_dh_groups.push_back(group); + } + else + { + m_curves.push_back(group); + } + } + } + +std::string Supported_Groups::curve_id_to_name(uint16_t id) { switch(id) { @@ -302,12 +318,23 @@ std::string Supported_Elliptic_Curves::curve_id_to_name(uint16_t id) return BOTAN_HOUSE_ECC_CURVE_NAME; #endif + case 256: + return "ffdhe/ietf/2048"; + case 257: + return "ffdhe/ietf/3072"; + case 258: + return "ffdhe/ietf/4096"; + case 259: + return "ffdhe/ietf/6144"; + case 260: + return "ffdhe/ietf/8192"; + default: return ""; // something we don't know or support } } -uint16_t Supported_Elliptic_Curves::name_to_curve_id(const std::string& name) +uint16_t Supported_Groups::name_to_curve_id(const std::string& name) { if(name == "secp256r1") return 23; @@ -332,17 +359,39 @@ uint16_t Supported_Elliptic_Curves::name_to_curve_id(const std::string& name) return BOTAN_HOUSE_ECC_CURVE_TLS_ID; #endif - // Unknown/unavailable EC curves are ignored + if(name == "ffdhe/ietf/2048") + return 256; + if(name == "ffdhe/ietf/3072") + return 257; + if(name == "ffdhe/ietf/4096") + return 258; + if(name == "ffdhe/ietf/6144") + return 259; + if(name == "ffdhe/ietf/8192") + return 260; + + // Unknown/unavailable DH groups/EC curves are ignored return 0; } -std::vector<uint8_t> Supported_Elliptic_Curves::serialize() const +bool Supported_Groups::is_dh_group( const std::string& group_name ) + { + if(group_name == "ffdhe/ietf/2048" || group_name == "ffdhe/ietf/3072" + || group_name == "ffdhe/ietf/4096" || group_name == "ffdhe/ietf/6144" + || group_name == "ffdhe/ietf/8192") + { + return true; + } + return false; + } + +std::vector<uint8_t> Supported_Groups::serialize() const { std::vector<uint8_t> buf(2); - for(size_t i = 0; i != m_curves.size(); ++i) + for(size_t i = 0; i != m_groups.size(); ++i) { - const uint16_t id = name_to_curve_id(m_curves[i]); + const uint16_t id = name_to_curve_id(m_groups[i]); if(id > 0) { @@ -357,16 +406,16 @@ std::vector<uint8_t> Supported_Elliptic_Curves::serialize() const return buf; } -Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader, - uint16_t extension_size) +Supported_Groups::Supported_Groups(TLS_Data_Reader& reader, + uint16_t extension_size) { uint16_t len = reader.get_uint16_t(); if(len + 2 != extension_size) - throw Decoding_Error("Inconsistent length field in elliptic curve list"); + throw Decoding_Error("Inconsistent length field in supported groups list"); if(len % 2 == 1) - throw Decoding_Error("Elliptic curve list of strange size"); + throw Decoding_Error("Supported groups list of strange size"); len /= 2; @@ -376,7 +425,17 @@ Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader, const std::string name = curve_id_to_name(id); if(!name.empty()) - m_curves.push_back(name); + { + m_groups.push_back(name); + if(is_dh_group(name)) + { + m_dh_groups.push_back(name); + } + else + { + m_curves.push_back(name); + } + } } } diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h index ee3310563..221d8b46f 100644 --- a/src/lib/tls/tls_extensions.h +++ b/src/lib/tls/tls_extensions.h @@ -225,10 +225,11 @@ class Session_Ticket final : public Extension std::vector<uint8_t> m_ticket; }; + /** -* Supported Elliptic Curves Extension (RFC 4492) +* Supported Groups Extension (RFC 7919) */ -class Supported_Elliptic_Curves final : public Extension +class Supported_Groups final : public Extension { public: static Handshake_Extension_Type static_type() @@ -239,21 +240,28 @@ class Supported_Elliptic_Curves final : public Extension static std::string curve_id_to_name(uint16_t id); static uint16_t name_to_curve_id(const std::string& name); + static bool is_dh_group( const std::string& group_name ); + const std::vector<std::string>& curves() const { return m_curves; } + const std::vector<std::string>& dh_groups() const { return m_dh_groups; } std::vector<uint8_t> serialize() const override; - explicit Supported_Elliptic_Curves(const std::vector<std::string>& curves) : - m_curves(curves) {} + explicit Supported_Groups(const std::vector<std::string>& groups); - Supported_Elliptic_Curves(TLS_Data_Reader& reader, + Supported_Groups(TLS_Data_Reader& reader, uint16_t extension_size); - bool empty() const override { return m_curves.empty(); } + bool empty() const override { return m_groups.empty(); } private: + std::vector<std::string> m_groups; std::vector<std::string> m_curves; + std::vector<std::string> m_dh_groups; }; +// previously Supported Elliptic Curves Extension (RFC 4492) +using Supported_Elliptic_Curves = Supported_Groups; + /** * Supported Point Formats Extension (RFC 4492) */ diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h index ac6c1e1ad..767635830 100644 --- a/src/lib/tls/tls_messages.h +++ b/src/lib/tls/tls_messages.h @@ -110,6 +110,8 @@ class BOTAN_UNSTABLE_API Client_Hello final : public Handshake_Message std::vector<std::string> supported_ecc_curves() const; + std::vector<std::string> supported_dh_groups() const; + bool prefers_compressed_ec_points() const; std::string sni_hostname() const; diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 43926e314..0a7e78e65 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -10,6 +10,7 @@ #include <botan/tls_ciphersuite.h> #include <botan/tls_magic.h> #include <botan/tls_exceptn.h> +#include <botan/tls_extensions.h> #include <botan/internal/stl_util.h> #include <botan/pk_keys.h> #include <sstream> @@ -117,7 +118,11 @@ std::vector<std::string> Policy::allowed_ecc_curves() const bool Policy::allowed_ecc_curve(const std::string& curve) const { - return value_exists(allowed_ecc_curves(), curve); + if(!allowed_ecc_curves().empty()) + { + return value_exists(allowed_ecc_curves(), curve); + } + return value_exists(allowed_groups(), curve); } bool Policy::use_ecc_point_compression() const @@ -130,21 +135,56 @@ bool Policy::use_ecc_point_compression() const */ std::string Policy::choose_curve(const std::vector<std::string>& curve_names) const { - const std::vector<std::string> our_curves = allowed_ecc_curves(); + const std::vector<std::string> our_groups = allowed_groups(); - for(size_t i = 0; i != our_curves.size(); ++i) - if(value_exists(curve_names, our_curves[i])) - return our_curves[i]; + for(size_t i = 0; i != our_groups.size(); ++i) + if(!Supported_Groups::is_dh_group(our_groups[i]) + && value_exists(curve_names, our_groups[i])) + return our_groups[i]; return ""; // no shared curve } +/* +* Choose an FFDHE group to use +*/ +std::string Policy::choose_dh_group(const std::vector<std::string>& dh_groups) const + { + const std::vector<std::string> our_groups = allowed_groups(); + + for(size_t i = 0; i != our_groups.size(); ++i) + if(Supported_Groups::is_dh_group(our_groups[i]) + && value_exists(dh_groups, our_groups[i])) + return our_groups[i]; + + return ""; // no shared ffdhe group + } + std::string Policy::dh_group() const { // We offer 2048 bit DH because we can return "modp/ietf/2048"; } +std::vector<std::string> Policy::allowed_groups() const + { + // Default list is ordered by performance + return { + "x25519", + "secp256r1", + "secp521r1", + "secp384r1", + "brainpool256r1", + "brainpool384r1", + "brainpool512r1", + "ffdhe/ietf/2048", + "ffdhe/ietf/3072", + "ffdhe/ietf/4096", + "ffdhe/ietf/6144", + "ffdhe/ietf/8192" + }; + } + size_t Policy::minimum_dh_group_size() const { return 2048; @@ -502,6 +542,7 @@ void Policy::print(std::ostream& o) const print_vec(o, "signature_methods", allowed_signature_methods()); print_vec(o, "key_exchange_methods", allowed_key_exchange_methods()); print_vec(o, "ecc_curves", allowed_ecc_curves()); + print_vec(o, "groups", allowed_groups()); print_bool(o, "allow_insecure_renegotiation", allow_insecure_renegotiation()); print_bool(o, "include_time_in_hello_random", include_time_in_hello_random()); diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index 333cf0ee1..2d90de5c0 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -103,6 +103,11 @@ class BOTAN_PUBLIC_API(2,0) Policy virtual std::string choose_curve(const std::vector<std::string>& curve_names) const; /** + * Choose an FFHDE group to use + */ + virtual std::string choose_dh_group(const std::vector<std::string>& dh_group_names) const; + + /** * Allow renegotiation even if the counterparty doesn't * support the secure renegotiation extension. * @@ -156,6 +161,8 @@ class BOTAN_PUBLIC_API(2,0) Policy virtual std::string dh_group() const; + virtual std::vector<std::string> allowed_groups() const; + /** * Return the minimum DH group size we're willing to use * Default is currently 1024 (insecure), should be 2048 @@ -330,6 +337,9 @@ class BOTAN_PUBLIC_API(2,0) NSA_Suite_B_128 final : public Policy std::vector<std::string> allowed_ecc_curves() const override { return std::vector<std::string>({"secp256r1"}); } + std::vector<std::string> allowed_groups() const override + { return allowed_ecc_curves(); } + size_t minimum_signature_strength() const override { return 128; } bool allow_tls10() const override { return false; } @@ -375,6 +385,12 @@ class BOTAN_PUBLIC_API(2,0) BSI_TR_02102_2 final : public Policy return std::vector<std::string>({"brainpool512r1", "brainpool384r1", "brainpool256r1", "secp384r1", "secp256r1"}); } + std::vector<std::string> allowed_groups() const override + { + return std::vector<std::string>({"brainpool512r1", "brainpool384r1", "brainpool256r1", "secp384r1", + "secp256r1", "ffdhe/ietf/8192", "ffdhe/ietf/6144", "ffdhe/ietf/4096", "ffdhe/ietf/3072", "ffdhe/ietf/2048"}); + } + bool allow_insecure_renegotiation() const override { return false; } bool allow_server_initiated_renegotiation() const override { return true; } bool server_uses_own_ciphersuite_preferences() const override { return true; } @@ -451,6 +467,8 @@ class BOTAN_PUBLIC_API(2,0) Text_Policy : public Policy std::vector<std::string> allowed_ecc_curves() const override; + std::vector<std::string> allowed_groups() const override; + bool use_ecc_point_compression() const override; bool allow_tls10() const override; diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index c0e853a80..fb8317a1c 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -168,6 +168,9 @@ uint16_t choose_ciphersuite( const bool have_shared_ecc_curve = (policy.choose_curve(client_hello.supported_ecc_curves()) != ""); + const bool have_shared_dh_group = + (policy.choose_dh_group(client_hello.supported_dh_groups()) != ""); + /* Walk down one list in preference order */ @@ -190,9 +193,13 @@ uint16_t choose_ciphersuite( if(suite.valid() == false) continue; + // TODO supported groups SHOULD have preference over ciphersuite list if(suite.ecc_ciphersuite() && have_shared_ecc_curve == false) continue; + if(suite.kex_algo() == "DH" && have_shared_dh_group == false) + continue; + // For non-anon ciphersuites if(suite.sig_algo() != "") { diff --git a/src/lib/tls/tls_text_policy.cpp b/src/lib/tls/tls_text_policy.cpp index ef5799339..345e6005f 100644 --- a/src/lib/tls/tls_text_policy.cpp +++ b/src/lib/tls/tls_text_policy.cpp @@ -108,6 +108,11 @@ std::string Text_Policy::dh_group() const return get_str("dh_group", Policy::dh_group()); } +std::vector<std::string> Text_Policy::allowed_groups() const + { + return get_list("groups", Policy::allowed_groups()); + } + size_t Text_Policy::minimum_ecdh_group_size() const { return get_len("minimum_ecdh_group_size", Policy::minimum_ecdh_group_size()); diff --git a/src/tests/data/tls-policy/bsi.txt b/src/tests/data/tls-policy/bsi.txt index 763c05219..9879b87f5 100644 --- a/src/tests/data/tls-policy/bsi.txt +++ b/src/tests/data/tls-policy/bsi.txt @@ -10,6 +10,7 @@ macs=AEAD SHA-384 SHA-256 key_exchange_methods=ECDH DH PSK ECDHE_PSK DHE_PSK signature_methods=ECDSA RSA DSA ecc_curves=brainpool512r1 brainpool384r1 brainpool256r1 secp384r1 secp256r1 +groups=brainpool512r1 brainpool384r1 brainpool256r1 secp384r1 secp256r1 ffdhe/ietf/8192 ffdhe/ietf/6144 ffdhe/ietf/4096 ffdhe/ietf/3072 ffdhe/ietf/2048 minimum_dh_group_size=2000 minimum_dsa_group_size=2000 minimum_ecdh_group_size=250 diff --git a/src/tests/data/tls-policy/suiteb.txt b/src/tests/data/tls-policy/suiteb.txt index 51d8fec12..7c0b3e7d8 100644 --- a/src/tests/data/tls-policy/suiteb.txt +++ b/src/tests/data/tls-policy/suiteb.txt @@ -17,6 +17,7 @@ server_uses_own_ciphersuite_preferences = true negotiate_encrypt_then_mac = true session_ticket_lifetime = 86400 dh_group = modp/ietf/2048 +groups = secp256r1 minimum_dh_group_size = 2048 minimum_ecdh_group_size = 255 minimum_rsa_bits = 2048 diff --git a/src/tests/data/tls/client_hello.vec b/src/tests/data/tls/client_hello.vec index aa8c03258..827f2ea4d 100644 --- a/src/tests/data/tls/client_hello.vec +++ b/src/tests/data/tls/client_hello.vec @@ -47,15 +47,15 @@ Buffer = 030320f3dc33f90be6509e6133a1819f2b80fe6ccc6268d9195ca4ead7504ffe7e2a000 Protocol = 0303 Exception = Invalid argument Decoding error: Bad extension size -#invalid length of the elliptic curve extension (0xf01c instead of 0x001c) +#invalid length of the supported groups extension (0xf01c instead of 0x001c) Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000af01c001a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101 Protocol = 0303 -Exception = Invalid argument Decoding error: Inconsistent length field in elliptic curve list +Exception = Invalid argument Decoding error: Inconsistent length field in supported groups list -#invalid length of the elliptic curve extension (0xf01a instead of 0x001a) +#invalid length of the supported groups extension (0xf01a instead of 0x001a) Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000a001cf01a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101 Protocol = 0303 -Exception = Invalid argument Decoding error: Inconsistent length field in elliptic curve list +Exception = Invalid argument Decoding error: Inconsistent length field in supported groups list #invalid length of the session ticket extension Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000a001c001a00170019001c001b0018001a0016000e000d000b000c0009000a002300ff000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101 diff --git a/src/tests/test_dl_group.cpp b/src/tests/test_dl_group.cpp index baa2fdc9d..d402931c5 100644 --- a/src/tests/test_dl_group.cpp +++ b/src/tests/test_dl_group.cpp @@ -133,6 +133,12 @@ class DL_Group_Tests final : public Test "dsa/jce/1024", "dsa/botan/2048", "dsa/botan/3072", + + "ffdhe/ietf/2048", + "ffdhe/ietf/3072", + "ffdhe/ietf/4096", + "ffdhe/ietf/6144", + "ffdhe/ietf/8192", }; Test::Result result("DL_Group named"); diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index 6f25d6903..c181e5c92 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -1346,15 +1346,18 @@ class TLS_Unit_Tests final : public Test test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", { { "use_ecc_point_compression", "true" } }); test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-256/GCM", "AEAD", - { { "ecc_curves", "secp521r1" } }); + { { "groups", "secp521r1" } }); test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", - { { "ecc_curves", "brainpool256r1" } }); + { { "groups", "brainpool256r1" } }); #if defined(BOTAN_HAS_CURVE_25519) test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", - { { "ecc_curves", "x25519" } }); + { { "groups", "x25519" } }); #endif + test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-128/GCM", "AEAD", + { { "groups", "ffdhe/ietf/2048" } }); + std::unique_ptr<Botan::Credentials_Manager> creds_with_client_cert(create_creds(rng, true)); test_modern_versions(results, *client_ses, *server_ses, *creds_with_client_cert, "ECDH", "AES-256/GCM"); @@ -1388,7 +1391,7 @@ class TLS_Unit_Tests final : public Test #if defined(BOTAN_HOUSE_ECC_CURVE_NAME) test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", - { { "ecc_curves", BOTAN_HOUSE_ECC_CURVE_NAME } }); + { { "groups", BOTAN_HOUSE_ECC_CURVE_NAME } }); #endif return results; |