diff options
26 files changed, 829 insertions, 83 deletions
diff --git a/jstests/libs/cluster_title_foo.pem b/jstests/libs/cluster_title_foo.pem new file mode 100644 index 00000000000..51c5a1b0e11 --- /dev/null +++ b/jstests/libs/cluster_title_foo.pem @@ -0,0 +1,54 @@ +# Autogenerated file, do not edit. +# Generate using jstests/ssl/x509/mkcert.py --config jstests/ssl/x509/certs.yml cluster_title_foo.pem +# +# Alternate certificate for intracluster auth including the title attribute set to foo. +-----BEGIN CERTIFICATE----- +MIIDjzCCAnegAwIBAgIEWd0RDTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV +UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO +BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs +IFRlc3QgQ0EwHhcNMjMwMzIyMDIzODIyWhcNMjUwNjIzMDIzODIyWjB/MQswCQYD +VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp +dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEUMBIGA1UEAwwL +Y2x1c3RlcnRlc3QxDDAKBgNVBAwMA2ZvbzCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKtYXLqpGhTggA2fItGZDqGwmPmUWpMpazBZ1vMxyvWeLQvso9Pk +Ubz+zXT0MP+XtjteoqUwNcfRViSiv2wiIttBD3VlGH3dGJXSnQaMMjE1MORkkjHJ +qeSZZA75QEpfyRhx7Tc+JEIwQx1Ptrrt1k9rQv58x1N8zN27Eqsqw3f9dq4XjpCs +XRBcOOSjVyHRKli5j1wxFLDNxBtr5+i5LfmWOgPY/KSQtE0cRqFXTxajHuMaRUtl +z9QMKRKc2uN3E7fA1Fa8IboT4mhG6mY9xO2rMf0cV4ZuMa3LimwG4KnTnii8cz8g +fXPDENvdI4/Wm6YuUlQRlfu6v77Mb0UEfW8CAwEAAaMeMBwwGgYDVR0RBBMwEYIJ +bG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQCdZZaJZN0X1htNTL1I +/ENBqZ5NYXyQi24yMJbRz+hVTFaR0gaecAG5A388YbcjmO1yLZcpzI4oHDSInc0Z +1kS8Zsriqfkh4ZQsWeHV9LImclecpYK2l0VB6YOpTOS2f75+PEaRSEYiYWEwERrk +q5IVodd59c5Mn8GUUrJVlVpNiwX1w0J9+qiUtmuQqrORpt6hbV1DGwXrMQgpprys +tZiEOxRUEyGTTtMoxktsGbT0o6Z+YAQRl90UVB7rPCpzwuJECFi0JXH28cIfncnr +8HVnEhxsPg4HHQmb5Ykq/gxNbAWSQAey3fP2NKosGnRKDJbd1ivyvvQNWya3DLIW +dbnN +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrWFy6qRoU4IAN +nyLRmQ6hsJj5lFqTKWswWdbzMcr1ni0L7KPT5FG8/s109DD/l7Y7XqKlMDXH0VYk +or9sIiLbQQ91ZRh93RiV0p0GjDIxNTDkZJIxyankmWQO+UBKX8kYce03PiRCMEMd +T7a67dZPa0L+fMdTfMzduxKrKsN3/XauF46QrF0QXDjko1ch0SpYuY9cMRSwzcQb +a+fouS35ljoD2PykkLRNHEahV08Wox7jGkVLZc/UDCkSnNrjdxO3wNRWvCG6E+Jo +RupmPcTtqzH9HFeGbjGty4psBuCp054ovHM/IH1zwxDb3SOP1pumLlJUEZX7ur++ +zG9FBH1vAgMBAAECggEAIQ63NTwS0BxQGFCvgwiojgFoQh6hKus+xuFOWzUsFx8h +Sb+qC+Ns8a2nLf0+xtEaU3H6pywZ9CcrG35auB4N44c12Exc4Uuaxq0Ppoe910iP +2kCdBAYIRRZi+5CTGsZIIfM49QOEM1DkYe9TLdVdF412K2sfebgGPnEtNODXPXrU +P0iLqxXRJmiWMZoxzbxNATMS8LkUG4gjfDeuGJZD1QFoun6hbCT4W6B2CgVnSpM1 +8Njys39V55wjAsfaKm4gpzeNRj5V0iw/G++G43uCVUQntTR/kzMABsfYFIWmfuOq +E50VteYwzlxskQZxqAPcw/7QmZNCANIfEEWFw3hmAQKBgQDgCiYlquODGUTcDydF +jzmZ3nnpacvBQ9KVO8IwpOg0v63EGXokvhVBigUszYTnqdlnihTJxkccXeCr21G7 +pL1tqq8qKQga46MH1B4DF7xYftwwYewEzXYIfYfMkJaxPw3Q9xrWU0y2pbHUY7zg +0odpV5IFkhyRpig3vdS15gqjQQKBgQDDydQx1XniYh72lX89Od5fXnfubzJJiG5J +GzSP0Z4GMusEX6cV4VTjZydDunv22nmHUj2yVtXIyFST1VJ5A2/OmSwjN8Dm/91E +/fTaSa3Eh/H5EzUV6EtuZXnIdYWBM/tQfQwViA2gph2mIMLUD7kxVo5G6y6wL+kw +kgDqWRnkrwKBgQC0v1thXkoo9VT5mPwdAVz+R1/hsSniZR5aqZiUeCaij9XX9Jn3 +VKd/daORLsm/wOcVwm/dDatHNnHRFKMPGOx+soqZH/ta/jYEVdxUsGySlN595jJs ++Xn1hZjur+PzYaR65zDuosusO2eJq2GxnAgFM9IpzmRgGUYvGmamzc3dQQKBgHrB +2iTgx4oUoXtUIrI9zVqYfbPmzm3id9uojh06fc0/MbHNU5LZdIMcUzcY/s65Dwe0 +nfBql6JLURRb5VjwubKcwVrXg0CS3qZ6YIJZPfWCk0nrLBavTlRKlcAFR47KC+Hc +da4uXvUCEobt9ZpGvYPc1FpM7ToU4C3O7XoCIcULAoGAD7W2C2tiHepHUlbLCiEt +fHoyoWVc1v1xPRdw/lNHVkopHyxB7Zg8nf2ei9kv+6ECdqmNk6qiYVtFMd+gxK3e +G5sgEZ2GazACraR9snz+iBOyYm+CoKJd1YzeyuFIs3hdq0++QQAm9XDaTu6C8HEM +bkhlGRJcQyaN32bPtRXkymY= +-----END PRIVATE KEY----- diff --git a/jstests/libs/cluster_title_foo.pem.digest.sha1 b/jstests/libs/cluster_title_foo.pem.digest.sha1 new file mode 100644 index 00000000000..2e6c630d0f4 --- /dev/null +++ b/jstests/libs/cluster_title_foo.pem.digest.sha1 @@ -0,0 +1 @@ +AAA79606BF68AE2AFA2A0F37F4DCD09FFCFD8295
\ No newline at end of file diff --git a/jstests/libs/cluster_title_foo.pem.digest.sha256 b/jstests/libs/cluster_title_foo.pem.digest.sha256 new file mode 100644 index 00000000000..21bcc294a52 --- /dev/null +++ b/jstests/libs/cluster_title_foo.pem.digest.sha256 @@ -0,0 +1 @@ +63EF60AFA384EAE126790C8CE5EE438F5956C77378D8997AD1644DBCC310F3DB
\ No newline at end of file diff --git a/jstests/libs/cluster_title_foo_no_o_ou_dc.pem b/jstests/libs/cluster_title_foo_no_o_ou_dc.pem new file mode 100644 index 00000000000..b3dff850c96 --- /dev/null +++ b/jstests/libs/cluster_title_foo_no_o_ou_dc.pem @@ -0,0 +1,53 @@ +# Autogenerated file, do not edit. +# Generate using jstests/ssl/x509/mkcert.py --config jstests/ssl/x509/certs.yml cluster_title_foo_no_o_ou_dc.pem +# +# Alternate certificate for intracluster auth including the title attribute set to foo without O, OU, or DC. +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIER0TcWzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV +UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO +BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs +IFRlc3QgQ0EwHhcNMjMwMzIyMDIzODUyWhcNMjUwNjIzMDIzODUyWjBcMRQwEgYD +VQQDDAtjbHVzdGVydGVzdDEMMAoGA1UEDAwDZm9vMQswCQYDVQQGEwJVUzERMA8G +A1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwpF7T1FoPnfAHotkAv5NRotQekIebAqHW +ohdeQiqmJoIMJ58qZOaTaNm+HMRiPo6/PYuKqup7w9nkbBO6xRK6+N8nn3IsrOVl +MOuERahyCcjEBRStZL/QiDSOK7FzBwLsnx/wSgNWisOzi840h0+OLmtpEK4kjxgg +sbH5GFEObfWX4OgHtjdf4MTn/EZkyb643MQT6aD8/qQ0/Ai0ptKCbuCfycondK6U +Tzps9vA61gXy/KwPhYfs9BVeWQAP7XHZvv7Lqgg5yciEC+qBwR3/pCYUhNqECndj +VY0Uffp/uH5snBRNfS1+/p9jIo+t0nq3UXVjfz+Fl1Uwndp8wtaNAgMBAAGjHjAc +MBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEA +E4q9YQX7PJ3IwibFNDpmwnb/mDHXQyhYdJsh7eRmdrF60TEMiXdYV+NMpVf/j1qV +bXiV7TskcNkqIK+88wbgDeR0gen+MhAyHCSe5B7QwRsuQ+8elsN84urmu9fddSKw +XycjivcqpqTGSyndWy5FAIfJ2SepZswgUofKcYOju36y6Ai5UBCQA1lNTwQHpQ8L +nZbf/mcqtQ0Op9y+UaT8r+L/ju9rNTVw96fDq4oJNXHZQgFUKZrv73RsJJaj8v5X +w0rYEQn0i3hIlap9clp4dXqFeqwrRxa5nI838p6DvjyMzBagMC6RVEHHI/JHAfzF +yy9y0ma7HQ32Lg5XspPrGw== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwpF7T1FoPnfAH +otkAv5NRotQekIebAqHWohdeQiqmJoIMJ58qZOaTaNm+HMRiPo6/PYuKqup7w9nk +bBO6xRK6+N8nn3IsrOVlMOuERahyCcjEBRStZL/QiDSOK7FzBwLsnx/wSgNWisOz +i840h0+OLmtpEK4kjxggsbH5GFEObfWX4OgHtjdf4MTn/EZkyb643MQT6aD8/qQ0 +/Ai0ptKCbuCfycondK6UTzps9vA61gXy/KwPhYfs9BVeWQAP7XHZvv7Lqgg5yciE +C+qBwR3/pCYUhNqECndjVY0Uffp/uH5snBRNfS1+/p9jIo+t0nq3UXVjfz+Fl1Uw +ndp8wtaNAgMBAAECggEABZWsydW04zmDFTq40aU86x/SxQScxPHYXAjT5E8DOi2N +fwThq111TMPL3o7aRqDjsngnqUKuFyuh/+7K0OTaKr8jjwUjfvYYapKZX500LibR +CiF+/dxplBY6UyRef9yA4ypEwDwWzu2kMlEBO/frM/uTucalOtKrWJ1FmzKBnYse +8H9zLyKbc96xk6IiFYlBqe6O6JT6mZtBHwz59zVmuJ7eP0V8Se8ZTA1MEE3P+ORR +/9xLURQc0hvfDFwSnM/gKAuwB3tpnJsEUmRCX0WBBCEiEJ+FaQ5yAihmfRv9AH8c +dFR/7XuKEMN5jetR4khjB2eBY26SXRzTQ8qE9fujoQKBgQDonTDu6EAa0yoySjQ+ +q3KW2Ir4Egqw3kJfBQ3ZBjtsRvbBsl0S0rEfq2EfgusKvIz9sVDLEGhrOnn8zhKM +CWkaikZORwniRtGUpMdsbw7UfUHaSDi/12kqD7vKXs3bJWrQsRVl3yHMYaDHWAUF +L9q9rvD7AD12bFMH8cBnGjmuFwKBgQDCZp+0G8fUlVgACwmMNnToOT/mzQEjsUlG +4ReS/o889pPvtpm+Ul5XK1Pl1gvcwfSo2hkzXBht95Sj5t7L4qBkK2naoN1LgbfX +R/fLuMQLCYgUOs3UbOUfyOy1LfgEHINuDHVaK7RkiWhuHE3/a+VKZvOnffL8Copu +xo1LyUHK+wKBgD8Rh5fu/pqHUHSMK/gl8g62LY+vDJkB2gr7StLh3rCv2O2Rl6yn +1YBZrh6mF2Y00yFhtx8nlrgkBbkmgl7XmliozwEgP6zLOL3No4hh4Cp6v6UYWdKh +7BCMbYUkCTp2vaxRpxSU2AwbGEWUNuA+JlexnALiAMgf/K81u834jVUHAoGBAIBP +K+m8zFBLoiGlJ1AcQV1lLAAyHyZnxW2688xZqEEcntgBNcigpRPzzRROCtZSTiGE +kk2L47PxTXJA15zKoAJ9hQiAVI+ZtrWpEqyr7vk5+U8g4OnsVe58t39+L8zG5Ril +sG8rmY0iBINouzJzDIvnF7rdLpuceXJUKr5yv7IxAoGBALxfb5KmvbdmBe43a5zo +J+Ig8oURUXbaWPb+8rpp+GaK3Hqf0Asjqlq2Fulz6TlwtkoRPl1yyebkNqz23p+T +0K52WJWnpxmXi5dRqDTJie/E8Tvm8ff/Xey04jDdS+J56WAAnC0P5O+Lq9BD6iNG +U3G/2LmJ+zn2NPeSxPyW3PSf +-----END PRIVATE KEY----- diff --git a/jstests/libs/cluster_title_foo_no_o_ou_dc.pem.digest.sha1 b/jstests/libs/cluster_title_foo_no_o_ou_dc.pem.digest.sha1 new file mode 100644 index 00000000000..25501110235 --- /dev/null +++ b/jstests/libs/cluster_title_foo_no_o_ou_dc.pem.digest.sha1 @@ -0,0 +1 @@ +ECA9EA58F05E2C92503D0F0B776BA5264A7D9D4B
\ No newline at end of file diff --git a/jstests/libs/cluster_title_foo_no_o_ou_dc.pem.digest.sha256 b/jstests/libs/cluster_title_foo_no_o_ou_dc.pem.digest.sha256 new file mode 100644 index 00000000000..87c6d2980e6 --- /dev/null +++ b/jstests/libs/cluster_title_foo_no_o_ou_dc.pem.digest.sha256 @@ -0,0 +1 @@ +D2AAD57CB4C330806DA153860BD0E908E3CFE4C41061986C3F27DBC1DD80B2D2
\ No newline at end of file diff --git a/jstests/libs/server_title_bar.pem b/jstests/libs/server_title_bar.pem new file mode 100644 index 00000000000..13d303c4fda --- /dev/null +++ b/jstests/libs/server_title_bar.pem @@ -0,0 +1,53 @@ +# Autogenerated file, do not edit. +# Generate using jstests/ssl/x509/mkcert.py --config jstests/ssl/x509/certs.yml server_title_bar.pem +# +# Server certificate including the title attribute set to bar. +-----BEGIN CERTIFICATE----- +MIIDijCCAnKgAwIBAgIEKf++izANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV +UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO +BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs +IFRlc3QgQ0EwHhcNMjMwMzIyMDIzOTE2WhcNMjUwNjIzMDIzOTE2WjB6MQswCQYD +VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp +dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEPMA0GA1UEAwwG +c2VydmVyMQwwCgYDVQQMDANiYXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCmLpAVBx01DYjNf4ElBIZvtYm3JXsOAYa5sYhSXHzxMA7t6xBpzynrXqxt +WDBwVlL+MEEoBi4lP7TBiBD9aZ/6agukeKliv7DuBZUSORIfu8aOsIXEe+U+F35q +WvCNod8SpQrxvjvvLbQsJCD+zdrzzIVOCgYToAlDb0znu8fXxFQ2gOPbJEu60aX1 +ca6hPA8+rmbt5KfPJ+fIPV/onhaiMuUklTX7PlntMhYgGYANFAP6fVw2OIgeGXjn +67z+ZD14EQ0reSfzqrKEbvqzrr8MJJ2wJYoYrT/Atu1JsLeudrb8ilmx26jHKa80 +OG3rxObOsg5z/0K2GsWR8AGXE0KzAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2Fs +aG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAFWe3TFS1T/GwfM3jE2g7MJQZ +30+p9HSfiC9kA3KPgyQE6lna17gyAS+YNaAQjC3pT1o3Dbanjs2Y2Ho/6JWAoeoj +puzrkgCH9IHIKhR/+JX/XwX+yY6txNzwgRvkdVpQkHZ4dp4LBb9sNQ+RA5T3rAlR +5g9/LwJbBGP0KSG2nxrsDEa3uYtm6HaqyjyNtCe6Hy9ez4qFq0fmKxnu2DnGgRwZ +O8hxW4rc/c5JRp5q1EuocpEHZTqZ1SigtdA1nBe6cA60gEOqOFfA7DrN4cM5vyk3 +fkxPGQ+uP/6tTSF8DHIL4lE9X8clKMYc8UU47SYCzN6NIKLBQcaQHTCb5V5ZwA== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmLpAVBx01DYjN +f4ElBIZvtYm3JXsOAYa5sYhSXHzxMA7t6xBpzynrXqxtWDBwVlL+MEEoBi4lP7TB +iBD9aZ/6agukeKliv7DuBZUSORIfu8aOsIXEe+U+F35qWvCNod8SpQrxvjvvLbQs +JCD+zdrzzIVOCgYToAlDb0znu8fXxFQ2gOPbJEu60aX1ca6hPA8+rmbt5KfPJ+fI +PV/onhaiMuUklTX7PlntMhYgGYANFAP6fVw2OIgeGXjn67z+ZD14EQ0reSfzqrKE +bvqzrr8MJJ2wJYoYrT/Atu1JsLeudrb8ilmx26jHKa80OG3rxObOsg5z/0K2GsWR +8AGXE0KzAgMBAAECggEAXNBmwofNpULg5D1RaNZlK2EOAI9bchAiKfZgt/dWBPMd +c341FZORyxZ+YTe/Hg7onXVf/rWs8jrpfqm7K33hzt+JjxuhJzj+3YGap6neWIDs +vecTXxD/kTVX8pjF/6SnzWcGfMwN92DkXz7yer2Ii1/wGAz7JdzdL5+rKUY0sGnd +EVs+f3y46hJ36ejD/DM0Lj9zVMzbOlA/Kiuq+uHGrH3DZBiL5qvzecn+3HM9o8kh +RzmtdllpsXq+P+MxFoea5OuIbq2vuNh4Cpg5PxEMbXhtPT0XwDf2NtN85CHL2glv +zI0CqaJ/kNLLLorNrbtekXuLllZPJezPxefyXcby0QKBgQDZi0sOKIAmVXc0whdj +MmsWpgtjs7S1NCgk09DiObSum/OWDMOYarFGdR/tDl30mzvpCbkk7QhNZcOZlNGX +szfi6jBm7ejbDaEexJ2U7gU3GaeZ13AqIDukAV2ArMwR40S25JyZ+jZvgsiUXhjv +nRFXFXaPMejYKPVX9CwLeXBvawKBgQDDju54KZYCKzPrZ0j+CbXTKVEC52Ch6G7S +g3AAOMHoVXGhn26jD3Uietnq3KI7oSHHeNkqQYYdbFCkjMkF25Rp9xlFILoLZ0VA +G6krXQ73z+BRPK9TPwzCaVxSXf+mxF4AIrGZbYsSZj+htm74opRk6+q3YrGzI9o1 +0ga84tez2QKBgQCCwT1wmhlEcTRAKrTh86j4KP9JgvcHvvyt/f5cKzEVjjjfpHZg +AyjgX3+7/VmtryxYSnbU4f+Ofa8Ofatokdjyc655/19pYozIMIdCv7m0v5/EUQBi +4ZLXZdasg6/4xHBFua0Cw6i6Z5Jl0xUL2I1WmVj0gpwgaKXmoqVilDBnVwKBgQCv +NfqXErtiSg8ElM+jPFP6U4RP07qSlcvlNPo+WJvza8qZgl0AH7NVJzjj4rZAMsgv +DimUYIynBArkw3bAltHMdyXe98l4uhgjriTNw1zLzyYt4u866Lyn2vpqmemaI0oN +WQhCbREzdQUCAJBAmHnYSj9L+1M3K6IwonKC/cNBUQKBgA+Jgzck+Q+mD/+ZvC1R +UWQmXG3IIMrpLRb+7eAanEDZX97sprY1E+Z05TbUuseR6IheED46JoviPtRYFRHV +ZBYcuhOd/BdDF3u38U08EAQkqaZnBzHM+780IphFRr3o/wH2JSwyeilSg8q1/XxO +VnZNKtdpmc5+EKlg3UhTb+T8 +-----END PRIVATE KEY----- diff --git a/jstests/libs/server_title_bar.pem.digest.sha1 b/jstests/libs/server_title_bar.pem.digest.sha1 new file mode 100644 index 00000000000..18a85e869e4 --- /dev/null +++ b/jstests/libs/server_title_bar.pem.digest.sha1 @@ -0,0 +1 @@ +31E9FDDBBAC424AA6377FF410698241361CCDC3F
\ No newline at end of file diff --git a/jstests/libs/server_title_bar.pem.digest.sha256 b/jstests/libs/server_title_bar.pem.digest.sha256 new file mode 100644 index 00000000000..8c5d7afe58c --- /dev/null +++ b/jstests/libs/server_title_bar.pem.digest.sha256 @@ -0,0 +1 @@ +2F1C21FFC8FD92864E6E26AC4052087AE9D34133EA1507D22155170F72903237
\ No newline at end of file diff --git a/jstests/libs/server_title_foo.pem b/jstests/libs/server_title_foo.pem new file mode 100644 index 00000000000..af938c1c7a8 --- /dev/null +++ b/jstests/libs/server_title_foo.pem @@ -0,0 +1,53 @@ +# Autogenerated file, do not edit. +# Generate using jstests/ssl/x509/mkcert.py --config jstests/ssl/x509/certs.yml server_title_foo.pem +# +# Server certificate including the title attribute set to foo. +-----BEGIN CERTIFICATE----- +MIIDijCCAnKgAwIBAgIELeq5MTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV +UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO +BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs +IFRlc3QgQ0EwHhcNMjMwMzIyMDIzODEyWhcNMjUwNjIzMDIzODEyWjB6MQswCQYD +VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp +dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEPMA0GA1UEAwwG +c2VydmVyMQwwCgYDVQQMDANmb28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC4Z+4f6WnJJzMqxxkShigpyObbCx0EElyzuSfECotm523C2jpVgplVh5Pn +eTL6eIUwwNN2d4XHR0VAvvU+tBS+MB42NrZt6MSh+tWCm/HN21/4zg48hdedGFwH +wDLTN94kRiaChkZ5aNzVqtLa+PtKX6UEYLvIHt+I7Y95hSvc1t1MSaobaEvLRjbU +fzihRGYYOXeLB0Yw3zurWi7wJ1Z9D8bIYikzgMkn1sPBPTmYHiqQIlxeDmQ5xmNJ +uRSjK6t16r8SVeNCTS85/pmWuy7hN7YnZXsdGXhP88sZxZOqdjEpsJsj5zGN0Ki0 +KC9NYasht7tZ8dMGmuPjsvo0dwyzAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2Fs +aG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEALbGw66c/ZoiuKT2u2i4dTjpV +L9xceahK9DWGV3syddTPkloER7vpyZzES6TrkC0Kw/3OMnSDaIy1hR3Gp9zCWhDX +UQLrqh+rnYMEPucG6oWxjPUovfmkWU0zdsTuiXmdJ0eWW/OLe1NPmt6WHlCG2cUl +BRJR23v2KfRfCL9YaOyLynsY49TXjEELyKD67csA3M6sYKbJ/pseM1TwDqB0Odyz +CSKDGQx98UsWGS2skuuhPgic8pgJITdp/WfUuI6JyvjpWRuxrHZykJSo38WhS6RG +rTyj35fDoapyFiJscx0dVrFkTrvptTlLRRxeIDzbZ40wR+EadnJ2/5DB0Nbu0A== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC4Z+4f6WnJJzMq +xxkShigpyObbCx0EElyzuSfECotm523C2jpVgplVh5PneTL6eIUwwNN2d4XHR0VA +vvU+tBS+MB42NrZt6MSh+tWCm/HN21/4zg48hdedGFwHwDLTN94kRiaChkZ5aNzV +qtLa+PtKX6UEYLvIHt+I7Y95hSvc1t1MSaobaEvLRjbUfzihRGYYOXeLB0Yw3zur +Wi7wJ1Z9D8bIYikzgMkn1sPBPTmYHiqQIlxeDmQ5xmNJuRSjK6t16r8SVeNCTS85 +/pmWuy7hN7YnZXsdGXhP88sZxZOqdjEpsJsj5zGN0Ki0KC9NYasht7tZ8dMGmuPj +svo0dwyzAgMBAAECggEAGxL3PSwx4dylgIRWxAd6Yhgi/Mn26qAfiCuJERlTOjqE +PPV5VxCjnpEXQAblWyzSsUO+SEhoFcf6/PSMYTZjTUEXTnJd+mkQZY/ERTbMG6M3 +xfnK0Uv9Sg1HhcPMMoKjVMQP5137ftvMgHpiFtAzZMoCGlBxgYI2442tYPQSaovJ +DqjPwz+Mn4PEskR0/xamhW+/dStbl2xaG9URPD5Mf2ZhWl8milMJC02Y/Ytm7igq +AENT06qMcaBtTQZrQubCmWHN+m/cHdGHLlsg5UN4SwsY5OaNrWqMFqrv8ouZEyC0 +4n5+X0kcU9FtXN6LSlLrlANdnAKKY9Sz5NNynlASYQKBgQD1jC33t4GYzqas+hpa +WGZfLu8aFdcyN5d2sXyMcPKuzULkytyn2GvfGkzcr4ngrewwM4EpotBxFRWN4CUl +cABzbehwFi0FM9PE/Ww25TALkBbtGmWxSmNuK9uIMwyCClas4T4fV8BS3pCsBC/p +Jp1QibOvRxtwTr8NRtWEPI9puwKBgQDAQXf0Q6xiBiM7Jwp7UtPEgEwY5aetTuYj +lLuasXMbAPpAhuZhBGlgpu4Xg6s/HnkQbuYoYcidoMGtTjwTIrnWtDC507kpdzQp +DkUJPBijiu6OMvQepJIilf45fyHnyDJ1q881PrrOzYikdHth9Ti61BD80YsHFAuF +51NJHhedaQKBgFTJsN3G6eNACGHWgt8Lg13+sOWLASH//DcqFl3QapxdmGm0evki +TC1fwYa6vptssw/52PHtnJhPtX+mFG2W/TDelNKPdcBEIy30bDeQcESt3pzE7rSH +gUn7rvSa3AjTVRahOHhOLsTuwXoEgB68DLpQslEl9p2TM3l8KiJdXxAdAoGAebT4 +SxnMNwHLq9a7O/bjOLI/ekNoMr6P0laFrRhI1f94bQD5NtGkJBuI/jnMXtjbqxuJ +eGbuqVrrQNsWDMce/lxzvC/cN/POgW8XJRF2R5HcEwkOoZdtK5foqF1jCWgjCXsK +YZqkh+Z1aiaTNSAYGa3GU0YTzRdTdCFNCCyUpoECgYAXQe6DhbcgRMv23eqml2Bk +dtcK8q8SJJ0t/onWItcI6CDo91nZSTkQ0A5aGjhUgTrBSnJFmbYjeyuOfqcVxDc6 ++I2Yn7ybBjpmZFQciOd0T2a79aZWKicjCM1PjJTQN4ghIt6/f/HtmcHoH4OBXfIp +zHWq9QZ48v0gu+1NZTx8xg== +-----END PRIVATE KEY----- diff --git a/jstests/libs/server_title_foo.pem.digest.sha1 b/jstests/libs/server_title_foo.pem.digest.sha1 new file mode 100644 index 00000000000..1c08ffd82a1 --- /dev/null +++ b/jstests/libs/server_title_foo.pem.digest.sha1 @@ -0,0 +1 @@ +AE9780F50789327BB1F6AD5343490CC2FDF559FD
\ No newline at end of file diff --git a/jstests/libs/server_title_foo.pem.digest.sha256 b/jstests/libs/server_title_foo.pem.digest.sha256 new file mode 100644 index 00000000000..1b7bfd18f16 --- /dev/null +++ b/jstests/libs/server_title_foo.pem.digest.sha256 @@ -0,0 +1 @@ +C2D4EE231C2704118F01DCD559987464EFDE8939873595386A8772B6274C70A1
\ No newline at end of file diff --git a/jstests/libs/server_title_foo_no_o_ou_dc.pem b/jstests/libs/server_title_foo_no_o_ou_dc.pem new file mode 100644 index 00000000000..87e5d8964ed --- /dev/null +++ b/jstests/libs/server_title_foo_no_o_ou_dc.pem @@ -0,0 +1,53 @@ +# Autogenerated file, do not edit. +# Generate using jstests/ssl/x509/mkcert.py --config jstests/ssl/x509/certs.yml server_title_foo_no_o_ou_dc.pem +# +# Server certificate including the title attribute set to foo without O, OU, or DC. +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIEPUtD4TANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV +UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO +BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs +IFRlc3QgQ0EwHhcNMjMwMzIyMDIzODQxWhcNMjUwNjIzMDIzODQxWjBXMQ8wDQYD +VQQDDAZzZXJ2ZXIxDDAKBgNVBAwMA2ZvbzELMAkGA1UEBhMCVVMxETAPBgNVBAgM +CE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA/z49ZcRbY9ZWekDxYgPqwlNffxfXWVtKibaO/FtY +vI2Ey6ngyqTGCvZrJ1MWvKxaKoILrPIhjxGcREW/FQNb2TG/6kpnhbUeoYe0zy1w +/hxZv9mkSe3xmkxw0V4RmzmKfaxeGcsq5S8eNJ9SVX1CRLgyindO+bwkikzMdL7f +5VlVx2ry3t1Jnn1ncRAGBV+PgtoVqQgK5IYFONVcOsoaxikSzr5q6WW1NwrUNhOs +F/76LoTFvu14o/QmzxiXsSMLmdo9f/Ejimf1THOMEahmD2KFUnx0F3EzcY6dholF +mE1pEmytTN9LlnMK/xt2CsuOtjn7NHznX17GBSuF7LzX3QIDAQABox4wHDAaBgNV +HREEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBAHPVIMCg +kmfyKl7Ci5uJS1OCGAdjpaqoSlC2jz7xWOe8P2Hz9gluQNu38EyG9EHM4G1jktCV +T3KyfaEcQw/4bgz1QlMEio1xPSEsqwMswAzb4cDPbxI3MEyLkx4mIcYZXG614rlm +ZX6A4UzZ7dIXRPoETnEy6CUDiOBVmlrGfVqv6lqtx63yUSbDKwoF8HVpJxpSjgQt +qY6AWKHqohmUImwludPlmjxJLh49yJyOMvXHRPr+BMPM/UYKVJ9mx4YmLJxMZMz4 +GSzPKqiJRNczvT1T1qdInUfYa5DtTxYS7NK2ZfvDqtjllTszoUp18shg3P5+tGJa +2zKmcCXWNlcqkqY= +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD/Pj1lxFtj1lZ6 +QPFiA+rCU19/F9dZW0qJto78W1i8jYTLqeDKpMYK9msnUxa8rFoqggus8iGPEZxE +Rb8VA1vZMb/qSmeFtR6hh7TPLXD+HFm/2aRJ7fGaTHDRXhGbOYp9rF4ZyyrlLx40 +n1JVfUJEuDKKd075vCSKTMx0vt/lWVXHavLe3UmefWdxEAYFX4+C2hWpCArkhgU4 +1Vw6yhrGKRLOvmrpZbU3CtQ2E6wX/vouhMW+7Xij9CbPGJexIwuZ2j1/8SOKZ/VM +c4wRqGYPYoVSfHQXcTNxjp2GiUWYTWkSbK1M30uWcwr/G3YKy462Ofs0fOdfXsYF +K4XsvNfdAgMBAAECggEAKCBhyKDw+SYWHEwfZphVDM3Moo9d9JdMhY/ktLmrnqDk +8pu3UkRLOif5OopudaTm2+3r5fl+2x4aogURAD2x79hJYozl73hE44IRI8zyCZDt +byLJGDJHHEnOJqwSOoP2SMGTXZy6FqOsrPsrF3OEuob2sxwEl3BDklZ2ghgL3OM5 +IIVycNo7tEGjrH1p7Z0+5Uuwf3lNZxlItc17bOTRwAi9eVlIMyoLz/ocaJFt5C3Y +KgCzkQcvWjjJEVwlMe10u9yyjs51yKAqkBfREOVYrYcAQigH1QSKpeLqbVDULMcl +5CM0e9y1ZDZAeOsRFqCdFMYHVBB/PdlMxP2eM+12JQKBgQD/2SZUC75jF29ekgmx +FEePQ+LQAlnP2Hplo1TUp6mOIB4n75B/GXbhvh/Aw/bzkeOPSKpZMbOUDcHGDwNu +ul63BeZWC7hBV53/rJdLEbknafZo3Aw427foNhRscA6iyb8z+QzsgElRuQ2Po/qF +0vXYxBI48V9ANkEUxCnBjhs8xwKBgQD/ZP+L29//osaTdxyiVwMqmMxw1NOg72eJ +pE5h5anJ+Zdj+XlE1BOGnpz/J1OMCEmspa0py0zqlvBTuhB5l1AamgeSlqjt8u7a +T56ariCmwkDCHVRUDevXXAmzdHgp9c5SPNp1Ka7qj5vhTK3YpVGUtzcWRJxqWeCg +rHYL/Yl6OwKBgHF1U/j7iD+bWekfbCraKm3PFhtWn4t7nbPK/cicXaXIencNVw/2 +M/EiBiTPAom7TaXx/JE3aEKk4yS47bXB8lTJyf6ojdp0R33lhOZmgqyG4h5YTxc7 +4M+ag+4et27bdu5OaLvMnDcgkHH9rxB/oESzlr0n1Sy9opjZ8QaDxXJrAoGAAfDQ +iE2JbDXecGxtSUaD/aTfmNPlL8nh7YfUGKZYHfLJlbbllwJNi65U3xN7bQr7FFbF +9BVZZkbzWI+HZIUj1K/q8tA2RGieLAaC3AYKtXmwaEk0xNa+PgqzACwYZak6giF4 +P3+rlpi0xIeCoqzO6+RghMjMr3ozXMUyuHCaxNUCgYEAkas1e5PagZ1u5AjpXtN3 +SI5Wc7IwwtzJf3PCsT3ijYifo1NGG98xM5jJhr+6Sw9QYuocJ1+dY1iHKVdxsBAK +WN+jJqncuF1EMEDLJpCk//ecLygG4aXnVuT+HGe38+X1SWzpTshP0wmZQeixZOtv +gRcYsGOG1GGQc7R4PrXooY0= +-----END PRIVATE KEY----- diff --git a/jstests/libs/server_title_foo_no_o_ou_dc.pem.digest.sha1 b/jstests/libs/server_title_foo_no_o_ou_dc.pem.digest.sha1 new file mode 100644 index 00000000000..be0670f8b8f --- /dev/null +++ b/jstests/libs/server_title_foo_no_o_ou_dc.pem.digest.sha1 @@ -0,0 +1 @@ +0F500F3768A87910EAD0571578AB10A9E39F2122
\ No newline at end of file diff --git a/jstests/libs/server_title_foo_no_o_ou_dc.pem.digest.sha256 b/jstests/libs/server_title_foo_no_o_ou_dc.pem.digest.sha256 new file mode 100644 index 00000000000..38a0951e2a4 --- /dev/null +++ b/jstests/libs/server_title_foo_no_o_ou_dc.pem.digest.sha256 @@ -0,0 +1 @@ +602B89632680A18CC323E067301487BB97A7F49CA9180ED116CC75AE06B2DA94
\ No newline at end of file diff --git a/jstests/ssl/x509/certs.yml b/jstests/ssl/x509/certs.yml index ebedbaba66d..f91b148a0a3 100644 --- a/jstests/ssl/x509/certs.yml +++ b/jstests/ssl/x509/certs.yml @@ -372,6 +372,81 @@ certs: <<: *server_pem_extensions mongoClusterMembership: foo +- name: 'server_title_foo.pem' + description: Server certificate including the title attribute set to foo. + Subject: + CN: 'server' + title: 'foo' + extensions: + subjectAltName: + DNS: localhost + IP: 127.0.0.1 + +- name: 'server_title_bar.pem' + description: Server certificate including the title attribute set to bar. + Subject: + CN: 'server' + title: 'bar' + extensions: + subjectAltName: + DNS: localhost + IP: 127.0.0.1 + +- name: 'cluster_title_foo.pem' + description: >- + Alternate certificate for intracluster auth including the title attribute set to foo. + Subject: + CN: 'clustertest' + title: 'foo' + extensions: + subjectAltName: + DNS: localhost + IP: 127.0.0.1 + +- name: 'server_title_foo_no_o_ou_dc.pem' + description: Server certificate including the title attribute set to foo without O, OU, or DC. + explicit_subject: true + Subject: + CN: 'server' + title: 'foo' + C: 'US' + ST: 'New York' + L: 'New York City' + extensions: + subjectAltName: + DNS: localhost + IP: 127.0.0.1 + +- name: 'server_title_bar_no_o_ou_dc.pem' + description: Server certificate including the title attribute set to bar without O, OU, or DC. + explicit_subject: true + Subject: + CN: 'server' + title: 'bar' + C: 'US' + ST: 'New York' + L: 'New York City' + extensions: + subjectAltName: + DNS: localhost + IP: 127.0.0.1 + +- name: 'cluster_title_foo_no_o_ou_dc.pem' + description: >- + Alternate certificate for intracluster auth including the title attribute set to foo + without O, OU, or DC. + explicit_subject: true + Subject: + CN: 'clustertest' + title: 'foo' + C: 'US' + ST: 'New York' + L: 'New York City' + extensions: + subjectAltName: + DNS: localhost + IP: 127.0.0.1 + # For tenant migration testing. - name: 'rs0.pem' description: General purpose server certificate file. diff --git a/jstests/sslSpecial/cluster_auth_x509_subject_attributes.js b/jstests/sslSpecial/cluster_auth_x509_subject_attributes.js new file mode 100644 index 00000000000..c473dd4c382 --- /dev/null +++ b/jstests/sslSpecial/cluster_auth_x509_subject_attributes.js @@ -0,0 +1,222 @@ +/** + * This test checks that tlsClusterAuthX509Attributes can be set in appropriate scenarios + * to specify the X.509 subject attributes that should be matched to consider a connectin client + * as a peer server node. + * + * @tags: [featureFlagConfigurableX509ClusterAuthn] + */ + +(function() { +'use strict'; + +load('jstests/ssl/libs/ssl_helpers.js'); + +if (determineSSLProvider() !== "openssl") { + print('Skipping test, tlsClusterAuthX509 options are only available with OpenSSL'); + return; +} + +const clusterMembershipAttributesDN = "title=foo, C=US, ST=New York, L=New York City"; +const clusterMembershipOverrideDN = + "C=US, ST=New York, L=New York, O=MongoDB Inc. (Rollover), OU=Kernel (Rollover), CN=server"; + +/** + * Member certificates whose subjects include OU, O and some attributes matched by + * tlsClusterAuthX509Attributes. + */ +// Subject: CN=server, title=foo, C=US, ST=New York, L=New York City, O=MongoDB, OU=Kernel +const serverTitleFooCert = 'jstests/libs/server_title_foo.pem'; +// Subject: CN=clusterTest, title=foo, C=US, ST=New York, L=New York City, O=MongoDB, OU=Kernel +const clusterTitleFooCert = 'jstests/libs/cluster_title_foo.pem'; + +/** + * Member certificates whose subjects do not include DC, OU, or O. + */ +// Subject: CN=server, title=foo, C=US, ST=New York, L=New York City +const serverTitleFooNoDefaultCert = 'jstests/libs/server_title_foo_no_o_ou_dc.pem'; +// Subject: CN=clusterTest, title=foo, C=US, ST=New York, L=New York City +const clusterTitleFooNoDefaultCert = 'jstests/libs/cluster_title_foo_no_o_ou_dc.pem'; + +/** + * Certificates that will not satisfy clusterMembershipAttributesDN. + */ +// Subject: CN=server, title=bar, C=US, ST=New York, L=New York City, O=MongoDB, OU=Kernel +const serverTitleBarCert = 'jstests/libs/server_title_bar.pem'; +// Subject: CN=server, C=US, ST=New York, L=New York City, O=MongoDB, OU=Kernel +const serverDefaultOnlyCert = 'jstests/libs/server.pem'; +// Subject: CN=clusterTest, C=US, ST=New York, L=New York City, O=MongoDB, OU=Kernel +const clusterDefaultOnlyCert = 'jstests/libs/cluster_cert.pem'; + +const serverCAFile = 'jstests/libs/ca.pem'; + +function assertNoStart(opts, errmsg) { + clearRawMongoProgramOutput(); + assert.throws(() => MongoRunner.runMongod(opts)); + assert(rawMongoProgramOutput().includes(errmsg)); +} + +function checkInvalidConfigurations() { + // Check that the option cannot be set unless clusterAuthMode == 'x509'. + const invalidClusterAuthModeOpts = { + auth: '', + tlsClusterAuthX509Attributes: clusterMembershipAttributesDN + }; + jsTest.log('No clusterAuthMode set'); + assertNoStart( + invalidClusterAuthModeOpts, + 'Cannot set clusterAuthX509.attributes when clusterAuthMode does not allow X.509'); + + jsTest.log('clusterAuthMode == keyFile'); + invalidClusterAuthModeOpts.clusterAuthMode = 'keyFile'; + assertNoStart( + invalidClusterAuthModeOpts, + 'Cannot set clusterAuthX509.attributes when clusterAuthMode does not allow X.509'); + + // Check that the server fails to start if both tlsClusterAuthX509Attributes and + // tlsX509ClusterAuthDNOverride are set. + const invalidTlsX509ClusterAuthDNOverrideOpts = { + auth: '', + tlsClusterAuthX509Attributes: clusterMembershipAttributesDN, + clusterAuthMode: 'x509', + tlsMode: 'preferTLS', + setParameter: { + tlsX509ClusterAuthDNOverride: clusterMembershipOverrideDN, + }, + tlsCertificateKeyFile: serverTitleFooCert, + tlsCAFile: serverCAFile, + tlsClusterFile: clusterTitleFooCert, + }; + jsTest.log('tlsX509ClusterAuthDNOverride also set'); + assertNoStart( + invalidTlsX509ClusterAuthDNOverrideOpts, + 'tlsClusterAuthX509Attributes and tlsX509ClusterAuthDNOverride cannot both be set at once'); + + // Check that the server fails to start if both tlsClusterAuthX509Attributes and + // tlsClusterAuthX509ExtensionValue are set. + const invalidClusterAuthX509ExtensionValOpts = { + auth: '', + tlsClusterAuthX509Attributes: clusterMembershipAttributesDN, + tlsClusterAuthX509ExtensionValue: 'foo', + clusterAuthMode: 'x509', + tlsMode: 'preferTLS', + tlsCertificateKeyFile: serverTitleFooCert, + tlsCAFile: serverCAFile, + tlsClusterFile: clusterTitleFooCert, + }; + jsTest.log('tlsClusterAuthX509ExtensionValue also set'); + assertNoStart( + invalidClusterAuthX509ExtensionValOpts, + 'net.tls.clusterAuthX509.attributes is not allowed when net.tls.clusterAuthX509.extensionValue is specified'); + + // Check that the server fails to start if the provided tlsClusterFile or tlsCertificateKeyFile + // do not contain the attributes + values specified by the tlsClusterAuthX509Attributes option. + // This ensures consistency between the member certificates provided to cluster nodes and the + // attributes they will be matching on. + const mismatchedTlsCertificateKeyFileOpts = { + auth: '', + tlsClusterAuthX509Attributes: clusterMembershipAttributesDN, + clusterAuthMode: 'x509', + tlsMode: 'preferTLS', + tlsCertificateKeyFile: serverDefaultOnlyCert, + tlsCAFile: serverCAFile, + tlsClusterFile: clusterDefaultOnlyCert, + }; + jsTest.log('Mismatched tlsCertificateKeyFile'); + assertNoStart( + mismatchedTlsCertificateKeyFileOpts, + "The server's outgoing certificate's DN does not contain the attributes specified in tlsClusterAuthX509Attributes"); +} + +function authX509(expectedUsername, port, clientCertificate) { + const evalCmd = String(function doAuthX509(db, authenticatedUsername) { + const external = db.getSiblingDB('$external'); + assert.commandWorked(external.runCommand({authenticate: 1, mechanism: 'MONGODB-X509'})); + const connStatus = assert.commandWorked(external.adminCommand({connectionStatus: 1})); + assert.eq(connStatus.authInfo.authenticatedUsers[0].user, authenticatedUsername); + }); + + const shell = runMongoProgram('mongo', + '--host', + 'localhost', + '--port', + port, + '--tls', + '--tlsCAFile', + serverCAFile, + '--tlsCertificateKeyFile', + clientCertificate, + '--eval', + evalCmd + ` doAuthX509(db, '${expectedUsername}');`); + assert.eq(shell, 0); +} + +function runValidMongodTest(opts, allAttrsMatch, wrongAttrValue, missingAttr) { + const conn = MongoRunner.runMongod(opts); + const admin = conn.getDB('admin'); + const external = conn.getDB('$external'); + assert.commandWorked(admin.runCommand({createUser: 'admin', pwd: 'admin', roles: ['root']})); + assert(admin.auth('admin', 'admin')); + + // Incoming certificate containing all attributes in tlsClusterAuthX509Attributes should result + // in successful auth as __system. + authX509(allAttrsMatch.user, conn.port, allAttrsMatch.certificate); + + // Incoming certificate containing all attributes in tlsClusterAuthX509Attributes but wrong + // value(s) should fail to auth as __system. After the subject of the cert exists as a user on + // $external, it will succeed as that user. + assert.throws(() => authX509('__system', conn.port, wrongAttrValue.certificate)); + assert.commandWorked(external.runCommand({createUser: wrongAttrValue.user, roles: []})); + authX509(wrongAttrValue.user, conn.port, wrongAttrValue.certificate); + + // Incoming certificate missing some attributes in tlsClusterAuthX509Attributes + // should fail to auth. After the subject of the cert exists as a user on $external, it will + // succeed as that user + assert.throws(() => authX509('__system', conn.port, missingAttr.certificate)); + assert.commandWorked(external.runCommand({createUser: missingAttr.user, roles: []})); + authX509(missingAttr.user, conn.port, missingAttr.certificate); + + MongoRunner.stopMongod(conn); +} + +checkInvalidConfigurations(); + +// First, run the tests with a valid set of member certificates that include one of +// DC, O, and OU but don't rely on them for membership detection. +let opts = { + auth: '', + tlsClusterAuthX509Attributes: clusterMembershipAttributesDN, + clusterAuthMode: 'x509', + tlsMode: 'preferTLS', + tlsCertificateKeyFile: serverTitleFooCert, + tlsCAFile: serverCAFile, + tlsClusterFile: clusterTitleFooCert, +}; +runValidMongodTest( + opts, + {user: '__system', certificate: clusterTitleFooCert}, + { + user: 'title=bar,CN=server,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US', + certificate: serverTitleBarCert + }, + { + user: 'CN=server,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US', + certificate: serverDefaultOnlyCert + }); + +// Now, use member certificates that don't have DC, O, or OU at all. This is +// valid if tlsClusterAuthX509Attributes is configured appropriately to specify +// attributes and values that the certificates have. +opts.tlsCertificateKeyFile = serverTitleFooNoDefaultCert; +opts.tlsClusterFile = clusterTitleFooNoDefaultCert; +runValidMongodTest( + opts, + {user: '__system', certificate: clusterTitleFooNoDefaultCert}, + { + user: 'title=bar,CN=server,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US', + certificate: serverTitleBarCert + }, + { + user: 'CN=server,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US', + certificate: serverDefaultOnlyCert + }); +})(); diff --git a/src/mongo/util/net/SConscript b/src/mongo/util/net/SConscript index 09b609aadb3..3d217c36ed4 100644 --- a/src/mongo/util/net/SConscript +++ b/src/mongo/util/net/SConscript @@ -263,6 +263,7 @@ if get_option('ssl') == 'on': 'network', 'ssl_manager', 'ssl_options_server', + 'ssl_types', ], ) diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp index 74c2f2c8748..de5370235eb 100644 --- a/src/mongo/util/net/ssl_manager.cpp +++ b/src/mongo/util/net/ssl_manager.cpp @@ -52,6 +52,7 @@ #include "mongo/util/icu.h" #include "mongo/util/net/ssl_options.h" #include "mongo/util/net/ssl_parameters_gen.h" +#include "mongo/util/net/ssl_types.h" #include "mongo/util/str.h" #include "mongo/util/synchronized_value.h" #include "mongo/util/text.h" @@ -278,57 +279,24 @@ std::pair<std::string, RFC4514Parser::ValueTerminator> RFC4514Parser::extractVal const auto getTLSVersionCounts = ServiceContext::declareDecoration<TLSVersionCounts>(); - -void canonicalizeClusterDN(std::vector<std::string>* dn) { - // remove all RDNs we don't care about - for (size_t i = 0; i < dn->size(); i++) { - std::string& comp = dn->at(i); - boost::algorithm::trim(comp); - if (!str::startsWith(comp.c_str(), "DC=") && // - !str::startsWith(comp.c_str(), "O=") && // - !str::startsWith(comp.c_str(), "OU=")) { - dn->erase(dn->begin() + i); - i--; - } - } - std::stable_sort(dn->begin(), dn->end()); -} - constexpr StringData kOID_DC = "0.9.2342.19200300.100.1.25"_sd; constexpr StringData kOID_O = "2.5.4.10"_sd; constexpr StringData kOID_OU = "2.5.4.11"_sd; -std::vector<SSLX509Name::Entry> canonicalizeClusterDN( - const std::vector<std::vector<SSLX509Name::Entry>>& entries) { - std::vector<SSLX509Name::Entry> ret; - - for (const auto& rdn : entries) { - for (const auto& entry : rdn) { - if ((entry.oid != kOID_DC) && (entry.oid != kOID_O) && (entry.oid != kOID_OU)) { - continue; - } - ret.push_back(entry); - } - } - std::stable_sort(ret.begin(), ret.end()); - return ret; -} - -struct DNValue { - explicit DNValue(SSLX509Name dn) - : fullDN(std::move(dn)), canonicalized(canonicalizeClusterDN(fullDN.entries())) {} - - SSLX509Name fullDN; - std::vector<SSLX509Name::Entry> canonicalized; +static const stdx::unordered_set<std::string> defaultMatchingAttributes = { + kOID_DC.toString(), + kOID_O.toString(), + kOID_OU.toString(), }; -synchronized_value<boost::optional<DNValue>> clusterMemberOverride; -boost::optional<std::vector<SSLX509Name::Entry>> getClusterMemberDNOverrideParameter() { - auto guarded_value = clusterMemberOverride.synchronize(); + +synchronized_value<boost::optional<SSLX509Name>> clusterAuthDNOverride; +boost::optional<SSLX509Name> getClusterAuthDNOverrideParameter() { + auto guarded_value = clusterAuthDNOverride.synchronize(); auto& value = *guarded_value; if (!value) { return boost::none; } - return value->canonicalized; + return value; } } // namespace @@ -410,36 +378,50 @@ void ClusterMemberDNOverride::append(OperationContext* opCtx, BSONObjBuilder* b, StringData name, const boost::optional<TenantId>&) { - auto value = clusterMemberOverride.get(); + auto value = clusterAuthDNOverride.get(); if (value) { - b->append(name, value->fullDN.toString()); + b->append(name, value->toString()); } } Status ClusterMemberDNOverride::setFromString(StringData str, const boost::optional<TenantId>&) { if (str.empty()) { - *clusterMemberOverride = boost::none; + *clusterAuthDNOverride = boost::none; return Status::OK(); } - auto swDN = parseDN(str); - if (!swDN.isOK()) { - return swDN.getStatus(); + auto swFullDN = parseDN(str); + if (!swFullDN.isOK()) { + return swFullDN.getStatus(); } - auto dn = std::move(swDN.getValue()); - auto status = dn.normalizeStrings(); + auto fullDN = std::move(swFullDN.getValue()); + auto status = fullDN.normalizeStrings(); if (!status.isOK()) { return status; } - DNValue val(std::move(dn)); - if (val.canonicalized.empty()) { - return {ErrorCodes::BadValue, - "Cluster member DN's must contain at least one O, OU, or DC component"}; + *clusterAuthDNOverride = {std::move(fullDN)}; + return Status::OK(); +} + +SSLX509Name filterClusterDN(const SSLX509Name& fullClusterDN, + const stdx::unordered_set<std::string>& filteredAttributes) { + std::vector<std::vector<SSLX509Name::Entry>> ret; + + for (const auto& rdn : fullClusterDN.entries()) { + std::vector<SSLX509Name::Entry> filteredRdn; + for (const auto& entry : rdn) { + if (filteredAttributes.contains(entry.oid)) { + filteredRdn.push_back(entry); + } + } + + if (!filteredRdn.empty()) { + ret.push_back(filteredRdn); + } } - *clusterMemberOverride = {std::move(val)}; - return Status::OK(); + return SSLX509Name(ret); } StatusWith<SSLX509Name> parseDN(StringData sd) try { @@ -690,6 +672,13 @@ Status SSLX509Name::normalizeStrings() { return Status::OK(); } +bool SSLX509Name::contains(const SSLX509Name& other) const { + return std::all_of( + other.entries().begin(), other.entries().end(), [this](const auto& attribute) { + return std::find(_entries.begin(), _entries.end(), attribute) != _entries.end(); + }); +} + StatusWith<std::string> SSLX509Name::getOID(StringData oid) const { for (const auto& rdn : _entries) { for (const auto& entry : rdn) { @@ -727,10 +716,39 @@ Status SSLConfiguration::setServerSubjectName(SSLX509Name name) { return status; } _serverSubjectName = std::move(name); - _canonicalServerSubjectName = canonicalizeClusterDN(_serverSubjectName.entries()); return Status::OK(); } +Status SSLConfiguration::setClusterAuthX509Attributes() try { + uassert( + ErrorCodes::InvalidSSLConfiguration, + "tlsClusterAuthX509Attributes and tlsX509ClusterAuthDNOverride cannot both be set at once", + sslGlobalParams.clusterAuthX509Attributes.empty() || + getClusterAuthDNOverrideParameter() == boost::none); + + if (!sslGlobalParams.clusterAuthX509Attributes.empty()) { + auto attributesAsDN = uassertStatusOK(parseDN(sslGlobalParams.clusterAuthX509Attributes)); + uassertStatusOK(attributesAsDN.normalizeStrings()); + + // The server's outgoing certificate subject DN and incoming certificate subject DN should + // match the criteria being used to determine other cluster member nodes. + uassert(ErrorCodes::InvalidSSLConfiguration, + "The server's outgoing certificate's DN does not contain the attributes specified " + "in tlsClusterAuthX509Attributes", + _serverSubjectName.contains(attributesAsDN)); + uassert(ErrorCodes::InvalidSSLConfiguration, + "The server's incoming certificate's DN does not contain the attributes specified " + "in tlsClusterAuthX509Attributes", + clientSubjectName.contains(attributesAsDN)); + + _clusterAuthX509Attributes = std::move(attributesAsDN); + } + + return Status::OK(); +} catch (const DBException& ex) { + return ex.toStatus(); +} + /** * The behavior of isClusterMember() is subtly different when passed * an SSLX509Name versus a StringData. @@ -743,21 +761,35 @@ Status SSLConfiguration::setServerSubjectName(SSLX509Name name) { * the server's distinguished name. */ bool SSLConfiguration::isClusterMember(SSLX509Name subject) const { - if (!subject.normalizeStrings().isOK()) { + if (auto status = subject.normalizeStrings(); !status.isOK()) { + LOGV2_WARNING(23220, "Unable to normalize client subject name", "error"_attr = status); return false; } - auto client = canonicalizeClusterDN(subject.entries()); - if (client.empty()) { - return false; + // If tlsClusterAuthX509Attributes have been specified, then subject is a cluster member as long + // as it contains all of the entries in _clusterAuthX509Attributes. + if (_clusterAuthX509Attributes) { + return subject.contains(*_clusterAuthX509Attributes); } - if (client == _canonicalServerSubjectName) { + // If not specified, check DC, O, and OU (the default matching attributes) from + // the server DN. + auto defaultFilteredSubjectDN = filterClusterDN(_serverSubjectName, defaultMatchingAttributes); + if (subject.contains(defaultFilteredSubjectDN)) { return true; } - auto altClusterDN = getClusterMemberDNOverrideParameter(); - return (altClusterDN && (client == *altClusterDN)); + // If the certificate did not match DC, O, and OU from the server DN, then the only way that it + // could still be accepted as a cluster member is if it contains the DC, O, and/or OU in the + // tlsClusterAuthDNOverride DN. + auto altClusterDN = getClusterAuthDNOverrideParameter(); + if (altClusterDN) { + auto defaultFilteredAltClusterDN = + filterClusterDN(*altClusterDN, defaultMatchingAttributes); + return subject.contains(defaultFilteredAltClusterDN); + } + + return false; } bool SSLConfiguration::isClusterMember(StringData subjectName) const { @@ -769,19 +801,8 @@ bool SSLConfiguration::isClusterMember(StringData subjectName) const { "error"_attr = swClient.getStatus()); return false; } - auto& client = swClient.getValue(); - auto status = client.normalizeStrings(); - if (!status.isOK()) { - LOGV2_WARNING(23220, - "Unable to normalize client subject name: {error}", - "Unable to normalize client subject name", - "error"_attr = status); - return false; - } - - auto canonicalClient = canonicalizeClusterDN(client.entries()); - return !canonicalClient.empty() && (canonicalClient == _canonicalServerSubjectName); + return isClusterMember(swClient.getValue()); } void SSLConfiguration::getServerStatusBSON(BSONObjBuilder* security) const { diff --git a/src/mongo/util/net/ssl_manager.h b/src/mongo/util/net/ssl_manager.h index 28b218530d5..6c8c98a91cf 100644 --- a/src/mongo/util/net/ssl_manager.h +++ b/src/mongo/util/net/ssl_manager.h @@ -446,6 +446,14 @@ std::string removeFQDNRoot(std::string name); std::string escapeRfc2253(StringData str); /** + * Generates a new SSLX509Name containing only the attributes requested in filteredAttributes. + * Note that multi-valued RDNs will be preserved if any of the attributes in the RDN are specified + * in filteredAttributes. + */ +SSLX509Name filterClusterDN(const SSLX509Name& fullClusterDN, + const stdx::unordered_set<std::string>& filterAttributes); + +/** * Parse a DN from a string per RFC 4514 */ StatusWith<SSLX509Name> parseDN(StringData str); diff --git a/src/mongo/util/net/ssl_manager_openssl.cpp b/src/mongo/util/net/ssl_manager_openssl.cpp index de847d52da0..64bb5751af0 100644 --- a/src/mongo/util/net/ssl_manager_openssl.cpp +++ b/src/mongo/util/net/ssl_manager_openssl.cpp @@ -1815,6 +1815,7 @@ SSLManagerOpenSSL::SSLManagerOpenSSL(const SSLParams& params, << params.sslPEMKeyFile); uassertStatusOK(_sslConfiguration.setServerSubjectName(std::move(serverSubjectName))); + uassertStatusOK(_sslConfiguration.setClusterAuthX509Attributes()); CertificateExpirationMonitor::get()->updateExpirationDeadline( _sslConfiguration.serverCertificateExpirationDate); diff --git a/src/mongo/util/net/ssl_manager_test.cpp b/src/mongo/util/net/ssl_manager_test.cpp index 8f6fef22362..a65b1db53e8 100644 --- a/src/mongo/util/net/ssl_manager_test.cpp +++ b/src/mongo/util/net/ssl_manager_test.cpp @@ -42,6 +42,7 @@ #include "mongo/logv2/log.h" #include "mongo/unittest/unittest.h" +#include "mongo/util/net/ssl_types.h" #if MONGO_CONFIG_SSL_PROVIDER == MONGO_CONFIG_SSL_PROVIDER_OPENSSL #include "mongo/util/net/dh_openssl.h" @@ -424,6 +425,105 @@ FlattenedX509Name flattenX509Name(const SSLX509Name& name) { return ret; } +TEST(SSLManager, FilterClusterDN) { + static const stdx::unordered_set<std::string> defaultMatchingAttributes = { + "0.9.2342.19200300.100.1.25", // DC + "2.5.4.10", // O + "2.5.4.11", // OU + }; + std::vector<std::pair<std::string, std::string>> tests = { + // Single-valued RDNs. + {"CN=server,OU=Kernel,O=MongoDB,DC=example,L=New York City,ST=New York,C=US", + "OU=Kernel,O=MongoDB,DC=example"}, + // Multi-valued RDN. + {"CN=server+OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US", "OU=Kernel,O=MongoDB"}, + // Multiple DC attributes. + {"CN=server,OU=Kernel,O=MongoDB,DC=example,DC=net,L=New York City,ST=New York,C=US", + "OU=Kernel,O=MongoDB,DC=example,DC=net"}, + }; + + for (const auto& test : tests) { + LOGV2(7498900, "Testing DN: ", "test_first"_attr = test.first); + auto swUnfilteredDN = parseDN(test.first); + auto swExpectedFilteredDN = parseDN(test.second); + + ASSERT_OK(swUnfilteredDN.getStatus()); + ASSERT_OK(swExpectedFilteredDN.getStatus()); + ASSERT_OK(swUnfilteredDN.getValue().normalizeStrings()); + ASSERT_OK(swExpectedFilteredDN.getValue().normalizeStrings()); + + auto actualFilteredDN = + filterClusterDN(swUnfilteredDN.getValue(), defaultMatchingAttributes); + ASSERT_TRUE(actualFilteredDN == swExpectedFilteredDN.getValue()); + } +}; + +TEST(SSLManager, DNContains) { + // Checks if the second RDN is contained by the first (order does not matter). + // The bool is the expected value. + std::vector<std::tuple<std::string, std::string, bool>> tests = { + // Single-valued RDNs positive case. + {"CN=server,OU=Kernel,O=MongoDB,DC=example,L=New York City,ST=New York,C=US", + "CN=server,L=New York City,ST=New York,C=US", + true}, + // Single-valued RDNs mismatched value. + {"CN=server,OU=Kernel,O=MongoDB,DC=example,L=New York City,ST=New York,C=US", + "CN=server,L=Yonkers,ST=New York,C=US", + false}, + // Single-valued RDNs missing attribute. + {"CN=server,OU=Kernel,O=MongoDB,DC=example,ST=New York,C=US", + "CN=server,L=Yonkers,ST=New York,C=US", + false}, + // Multi-valued RDN negative case (attribute value mismatch). + {"CN=server,OU=Kernel,O=MongoDB,L=New York City+ST=New York,C=US", + "CN=server,L=Yonkers+ST=New York", + false}, + // Multi-valued RDN negative case (matching attributes in single-value RDNs, first RDN needs + // to be filtered beforehand). + {"CN=server,OU=Kernel,O=MongoDB,L=New York City+ST=New York,C=US", + "CN=server,L=New York City", + false}, + // Multi-valued RDN negative case (input DN has attributes in single-value RDNs while match + // expects multi-valued RDN). + {"CN=server,OU=Kernel,O=MongoDB,L=New York City,ST=New York,C=US", + "CN=server,L=New York City+ST=New York", + false}, + // Multi-valued RDN positive case (full multi-valued RDN present in second). + {"CN=server,OU=Kernel,O=MongoDB,L=New York City+ST=New York,C=US", + "CN=server,L=New York City+ST=New York", + true}, + // Multiple attributes positive case (order should not matter). + {"CN=server,OU=Kernel,O=MongoDB,DC=net,DC=example,L=New York City,ST=New York,C=US", + "OU=Kernel,O=MongoDB,DC=example,DC=net", + true}, + // Multiple attributes positive case (missing in second, but should not matter). + {"CN=server,OU=Kernel,O=MongoDB,DC=example,DC=net,L=New York City,ST=New York,C=US", + "OU=Kernel,O=MongoDB,DC=example", + true}, + // Multiple attributes negative case (missing in first). + {"CN=server,OU=Kernel,O=MongoDB,DC=example,L=New York City,ST=New York,C=US", + "OU=Kernel,O=MongoDB,DC=example,DC=net", + false}, + }; + + for (const auto& test : tests) { + LOGV2(7498901, "Testing DN: ", "test_first"_attr = std::get<0>(test)); + auto swExternalDN = parseDN(std::get<0>(test)); + auto swMatchPatternDN = parseDN(std::get<1>(test)); + + ASSERT_OK(swExternalDN.getStatus()); + ASSERT_OK(swMatchPatternDN.getStatus()); + + auto externalDN = swExternalDN.getValue(); + auto matchPatternDN = swMatchPatternDN.getValue(); + + ASSERT_OK(externalDN.normalizeStrings()); + ASSERT_OK(matchPatternDN.normalizeStrings()); + + ASSERT_EQ(externalDN.contains(matchPatternDN), std::get<2>(test)); + } +}; + TEST(SSLManager, DNParsingAndNormalization) { std::vector<std::pair<std::string, FlattenedX509Name>> tests = { // Basic DN parsing diff --git a/src/mongo/util/net/ssl_options.h b/src/mongo/util/net/ssl_options.h index 41bb82c66ea..2f50b564074 100644 --- a/src/mongo/util/net/ssl_options.h +++ b/src/mongo/util/net/ssl_options.h @@ -73,6 +73,7 @@ struct SSLParams { std::string sslCipherConfig; // --tlsCipherConfig std::string sslCipherSuiteConfig; // --tlsCipherSuiteConfig std::string clusterAuthX509ExtensionValue; // --tlsClusterAuthX509ExtensionValue + std::string clusterAuthX509Attributes; // --tlsClusterAuthX509Attributes boost::optional<TLSCATrusts> tlsCATrusts; // --setParameter tlsCATrusts diff --git a/src/mongo/util/net/ssl_options_server.cpp b/src/mongo/util/net/ssl_options_server.cpp index 2f1e6f15179..a85acc3ff0c 100644 --- a/src/mongo/util/net/ssl_options_server.cpp +++ b/src/mongo/util/net/ssl_options_server.cpp @@ -254,6 +254,17 @@ MONGO_STARTUP_OPTIONS_POST(SSLServerOptions)(InitializerContext*) { params["net.tls.clusterAuthX509.extensionValue"].as<std::string>(); } + if (params.count("net.tls.clusterAuthX509.attributes")) { + uassert(ErrorCodes::BadValue, + "Unknown configuration option 'net.tls.clusterAuthX509.attributes'", + gFeatureFlagConfigurableX509ClusterAuthn.isEnabledAndIgnoreFCV()); + uassert(ErrorCodes::BadValue, + "Cannot set clusterAuthX509.attributes when clusterAuthMode does not allow X.509", + clusterAuthMode.allowsX509()); + sslGlobalParams.clusterAuthX509Attributes = + params["net.tls.clusterAuthX509.attributes"].as<std::string>(); + } + if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_allowSSL) { // allowSSL and x509 is valid only when we are transitioning to auth. if (clusterAuthMode.sendsX509() && !serverGlobalParams.transitionToAuth) { diff --git a/src/mongo/util/net/ssl_options_server.idl b/src/mongo/util/net/ssl_options_server.idl index 0311f3e74da..be97af32294 100644 --- a/src/mongo/util/net/ssl_options_server.idl +++ b/src/mongo/util/net/ssl_options_server.idl @@ -63,7 +63,10 @@ configs: hidden: true "net.tls.certificateKeyFile": - description: "Certificate and key file for TLS" + description: >- + Certificate and key file for TLS. Certificate is presented in response to inbound connections + always. Certificate is also presented for outbound connections if tlsClusterFile is not + specified. short_name: tlsCertificateKeyFile deprecated_name: "net.ssl.PEMKeyFile" deprecated_short_name: sslPEMKeyFile @@ -79,7 +82,9 @@ configs: redact: true "net.tls.clusterFile": - description: "Key file for internal TLS authentication" + description: >- + Certificate and key file for internal TLS authentication. Certificate is presented on outbound + connections if specified. short_name: tlsClusterFile deprecated_name: "net.ssl.clusterFile" deprecated_short_name: sslClusterFile @@ -95,7 +100,10 @@ configs: redact: true "net.tls.CAFile": - description: "Certificate Authority file for TLS" + description: >- + Certificate Authority file for TLS. Used to verify remote certificates presented in response + to outbound connections. Also used to verify remote certificates from inbound connections if + tlsClusterCAFile is not specified. short_name: tlsCAFile deprecated_name: "net.ssl.CAFile" deprecated_short_name: sslCAFile @@ -187,5 +195,13 @@ configs: for OID 1.3.6.1.4.1.34601.2.1.2 which contains the specified value. short_name: tlsClusterAuthX509ExtensionValue arg_vartype: String - # // TODO SERVER-74989 X.509 Subject Name Matching - # conflicts: "net.tls.clusterAuthX509.attributes" + conflicts: "net.tls.clusterAuthX509.attributes" + + "net.tls.clusterAuthX509.attributes": + description: >- + If specified, clients performing X.509 authentication must present a certificate with a + subject name with the exact attributes and values provided in this config option to be + treated as peer cluster nodes. + short_name: tlsClusterAuthX509Attributes + arg_vartype: String + conflicts: "net.tls.clusterAuthX509.extensionValue" diff --git a/src/mongo/util/net/ssl_types.h b/src/mongo/util/net/ssl_types.h index 6f859ee01aa..ed41e242ebb 100644 --- a/src/mongo/util/net/ssl_types.h +++ b/src/mongo/util/net/ssl_types.h @@ -34,6 +34,7 @@ #include "mongo/bson/util/builder.h" #include "mongo/db/auth/role_name.h" #include "mongo/stdx/unordered_set.h" +#include "mongo/util/synchronized_value.h" namespace mongo { @@ -65,7 +66,7 @@ public: explicit SSLX509Name(std::vector<std::vector<Entry>> entries) : _entries(std::move(entries)) {} /** - * Retreive the first instance of the value for a given OID in this name. + * Retrieve the first instance of the value for a given OID in this name. * Returns ErrorCodes::KeyNotFound if the OID does not exist. */ StatusWith<std::string> getOID(StringData oid) const; @@ -97,6 +98,12 @@ public: */ Status normalizeStrings(); + /** + * A SSLX509Name is said to contain another SSLX509Name if it contains all of the other + * SSLX509Name's entries. + */ + bool contains(const SSLX509Name& other) const; + private: std::vector<std::vector<Entry>> _entries; }; @@ -115,6 +122,11 @@ public: bool isClusterMember(SSLX509Name subjectName) const; void getServerStatusBSON(BSONObjBuilder*) const; Status setServerSubjectName(SSLX509Name name); + Status setClusterAuthX509Attributes(); + + const boost::optional<SSLX509Name>& getClusterAuthX509Attributes() { + return _clusterAuthX509Attributes; + } const SSLX509Name& serverSubjectName() const { return _serverSubjectName; @@ -126,7 +138,9 @@ public: private: SSLX509Name _serverSubjectName; - std::vector<SSLX509Name::Entry> _canonicalServerSubjectName; + + // DN provided via tlsClusterAuthX509.attributes. + boost::optional<SSLX509Name> _clusterAuthX509Attributes; }; } // namespace mongo |