TLS Client NSS: Rely on NSS 3.14 cipher suite defaults

Older versions needed application code to actually enable strong
ciphers, but this changed in version 3.14.
This commit is contained in:
Florian Weimer 2013-04-02 17:12:57 +02:00
parent c861995515
commit 04d4055034
4 changed files with 21 additions and 76 deletions

View file

@ -768,8 +768,13 @@
<title>Implementing TLS Clients With NSS</title> <title>Implementing TLS Clients With NSS</title>
<para> <para>
The following code shows how to implement a simple TLS client The following code shows how to implement a simple TLS client
using NSS. Note that the error handling needs replacing using NSS. These instructions apply to NSS version 3.14 and
before production use. later. Versions before 3.14 need different initialization
code.
</para>
<para>
Keep in mind that the error handling needs to be improved
before the code can be used in production.
</para> </para>
<para> <para>
Using NSS needs several header files, as shown in Using NSS needs several header files, as shown in
@ -781,17 +786,13 @@
xmlns:xi="http://www.w3.org/2001/XInclude" /> xmlns:xi="http://www.w3.org/2001/XInclude" />
</example> </example>
<para> <para>
Initializing the NSS library is a complex task (<xref Initializing the NSS library is shown in <xref
linkend="ex-Defensive_Coding-TLS-NSS-Init"/>). It is not linkend="ex-Defensive_Coding-TLS-NSS-Init"/>. This
thread-safe. By default, the library is in export mode, and initialization procedure overrides global state. We only call
all strong ciphers are disabled. Therefore, after creating <function>NSS_SetDomesticPolicy</function> if there are no
the <literal>NSSInitCContext</literal> object, we probe all strong ciphers available, assuming that it has already been
the strong ciphers we want to use, and check if at least one called otherwise. This avoids overriding the process-wide
of them is available. If not, we call cipher suite policy unnecessarily.
<function>NSS_SetDomesticPolicy</function> to switch to
unrestricted policy mode. This function replaces the existing
global cipher suite policy, that is why we avoid calling it
unless absolutely necessary.
</para> </para>
<para> <para>
The simplest way to configured the trusted root certificates The simplest way to configured the trusted root certificates
@ -825,11 +826,7 @@
function is de-facto part of the NSS public ABI, so it will function is de-facto part of the NSS public ABI, so it will
not go away.) Creating the TLS-capable file descriptor not go away.) Creating the TLS-capable file descriptor
requires a <emphasis>model</emphasis> descriptor, which is requires a <emphasis>model</emphasis> descriptor, which is
configured with the desired set of protocols and ciphers. configured with the desired set of protocols. The model
(The <literal>good_ciphers</literal> variable is part of <xref
linkend="ex-Defensive_Coding-TLS-NSS-Init"/>.) We cannot
resort to disabling ciphers not on a whitelist because by
default, the AES cipher suites are disabled. The model
descriptor is not needed anymore after TLS support has been descriptor is not needed anymore after TLS support has been
activated for the existing connection descriptor. activated for the existing connection descriptor.
</para> </para>

View file

@ -39,32 +39,6 @@ sockfd = -1; // Has been taken over by NSPR.
exit(1); exit(1);
} }
// Disable all ciphers (except RC4-based ciphers, for backwards
// compatibility).
const PRUint16 *const ciphers = SSL_GetImplementedCiphers();
for (unsigned i = 0; i &#60; SSL_GetNumImplementedCiphers(); i++) {
if (ciphers[i] != SSL_RSA_WITH_RC4_128_SHA
&#38;&#38; ciphers[i] != SSL_RSA_WITH_RC4_128_MD5) {
if (SSL_CipherPrefSet(model, ciphers[i], PR_FALSE) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: disable cipher %u: error %d: %s\n",
(unsigned)ciphers[i], err, PR_ErrorToName(err));
exit(1);
}
}
}
// Enable the strong ciphers.
for (const PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL;
++p) {
if (SSL_CipherPrefSet(model, *p, PR_TRUE) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: enable cipher %u: error %d: %s\n",
(unsigned)*p, err, PR_ErrorToName(err));
exit(1);
}
}
// Allow overriding invalid certificate. // Allow overriding invalid certificate.
if (SSL_BadCertHook(model, bad_certificate, (char *)host) != SECSuccess) { if (SSL_BadCertHook(model, bad_certificate, (char *)host) != SECSuccess) {
const PRErrorCode err = PR_GetError(); const PRErrorCode err = PR_GetError();

View file

@ -23,9 +23,9 @@ static const PRUint16 good_ciphers[] = {
}; };
// Check if the current policy allows any strong ciphers. If it // Check if the current policy allows any strong ciphers. If it
// doesn't, switch to the "domestic" (unrestricted) policy. This is // doesn't, set the cipher suite policy. This is not thread-safe
// not thread-safe and has global impact. Consequently, we only do // and has global impact. Consequently, we only do it if absolutely
// it if absolutely necessary. // necessary.
int found_good_cipher = 0; int found_good_cipher = 0;
for (const PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL; for (const PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL;
++p) { ++p) {

View file

@ -114,9 +114,9 @@ main(int argc, char **argv)
}; };
// Check if the current policy allows any strong ciphers. If it // Check if the current policy allows any strong ciphers. If it
// doesn't, switch to the "domestic" (unrestricted) policy. This is // doesn't, set the cipher suite policy. This is not thread-safe
// not thread-safe and has global impact. Consequently, we only do // and has global impact. Consequently, we only do it if absolutely
// it if absolutely necessary. // necessary.
int found_good_cipher = 0; int found_good_cipher = 0;
for (const PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL; for (const PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL;
++p) { ++p) {
@ -190,32 +190,6 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
// Disable all ciphers (except RC4-based ciphers, for backwards
// compatibility).
const PRUint16 *const ciphers = SSL_GetImplementedCiphers();
for (unsigned i = 0; i < SSL_GetNumImplementedCiphers(); i++) {
if (ciphers[i] != SSL_RSA_WITH_RC4_128_SHA
&& ciphers[i] != SSL_RSA_WITH_RC4_128_MD5) {
if (SSL_CipherPrefSet(model, ciphers[i], PR_FALSE) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: disable cipher %u: error %d: %s\n",
(unsigned)ciphers[i], err, PR_ErrorToName(err));
exit(1);
}
}
}
// Enable the strong ciphers.
for (const PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL;
++p) {
if (SSL_CipherPrefSet(model, *p, PR_TRUE) != SECSuccess) {
const PRErrorCode err = PR_GetError();
fprintf(stderr, "error: enable cipher %u: error %d: %s\n",
(unsigned)*p, err, PR_ErrorToName(err));
exit(1);
}
}
// Allow overriding invalid certificate. // Allow overriding invalid certificate.
if (SSL_BadCertHook(model, bad_certificate, (char *)host) != SECSuccess) { if (SSL_BadCertHook(model, bad_certificate, (char *)host) != SECSuccess) {
const PRErrorCode err = PR_GetError(); const PRErrorCode err = PR_GetError();