nss:set_cipher don't clobber the cipher list

The string is set by the user and needs to remain intact for proper
connection reuse etc.

Reported-by: Eric Musser
Fixes #8160
Closes #8161
This commit is contained in:
Daniel Stenberg 2021-12-17 23:40:11 +01:00
parent 7a92f865b4
commit 556a42edfb
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2

View file

@ -304,13 +304,14 @@ static char *nss_sslver_to_name(PRUint16 nssver)
} }
} }
static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, /* the longest cipher name this supports */
char *cipher_list) #define MAX_CIPHER_LENGTH 128
static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc *model,
const char *cipher_list)
{ {
unsigned int i; unsigned int i;
PRBool cipher_state[NUM_OF_CIPHERS]; const char *cipher;
PRBool found;
char *cipher;
/* use accessors to avoid dynamic linking issues after an update of NSS */ /* use accessors to avoid dynamic linking issues after an update of NSS */
const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers(); const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
@ -326,51 +327,52 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE); SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE);
} }
/* Set every entry in our list to false */
for(i = 0; i < NUM_OF_CIPHERS; i++) {
cipher_state[i] = PR_FALSE;
}
cipher = cipher_list; cipher = cipher_list;
while(cipher_list && (cipher_list[0])) { while(cipher && cipher[0]) {
const char *end;
char name[MAX_CIPHER_LENGTH + 1];
size_t len;
bool found = FALSE;
while((*cipher) && (ISSPACE(*cipher))) while((*cipher) && (ISSPACE(*cipher)))
++cipher; ++cipher;
cipher_list = strpbrk(cipher, ":, "); end = strpbrk(cipher, ":, ");
if(cipher_list) { if(end)
*cipher_list++ = '\0'; len = end - cipher;
else
len = strlen(cipher);
if(len > MAX_CIPHER_LENGTH) {
failf(data, "Bad cipher list");
return SECFailure;
} }
else if(len) {
memcpy(name, cipher, len);
name[len] = 0;
found = PR_FALSE; for(i = 0; i<NUM_OF_CIPHERS; i++) {
if(strcasecompare(name, cipherlist[i].name)) {
for(i = 0; i<NUM_OF_CIPHERS; i++) { /* Enable the selected cipher */
if(strcasecompare(cipher, cipherlist[i].name)) { if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) !=
cipher_state[i] = PR_TRUE; SECSuccess) {
found = PR_TRUE; failf(data, "cipher-suite not supported by NSS: %s", name);
break; return SECFailure;
}
found = TRUE;
break;
}
} }
} }
if(found == PR_FALSE) { if(!found && len) {
failf(data, "Unknown cipher in list: %s", cipher); failf(data, "Unknown cipher: %s", name);
return SECFailure;
}
if(cipher_list) {
cipher = cipher_list;
}
}
/* Finally actually enable the selected ciphers */
for(i = 0; i<NUM_OF_CIPHERS; i++) {
if(!cipher_state[i])
continue;
if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) {
failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
return SECFailure; return SECFailure;
} }
if(end)
cipher = ++end;
else
break;
} }
return SECSuccess; return SECSuccess;