diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h index db09425..437a822 100644 --- a/lib/ssl/ssl.h +++ b/lib/ssl/ssl.h @@ -387,6 +387,13 @@ SSL_IMPORT SECStatus SSL_DHEGroupPrefSet(PRFileDesc *fd, */ SSL_IMPORT SECStatus SSL_EnableWeakDHEPrimeGroup(PRFileDesc *fd, PRBool enabled); +/* SSL_CipherOrderSet sets the cipher suite preference order from |ciphers|, + * which must be an array of cipher suite ids of length |len|. All the given + * cipher suite ids must appear in the array that is returned by + * |SSL_GetImplementedCiphers| and may only appear once, at most. */ +SSL_IMPORT SECStatus SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, + unsigned int len); + /* SSLChannelBindingType enumerates the types of supported channel binding * values. See RFC 5929. */ typedef enum SSLChannelBindingType { diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c index 5c09f25..572bba9 100644 --- a/lib/ssl/ssl3con.c +++ b/lib/ssl/ssl3con.c @@ -13390,6 +13390,46 @@ SSL_SignatureMaxCount() { return MAX_SIGNATURE_ALGORITHMS; } +SECStatus +ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *ciphers, unsigned int len) +{ + /* |i| iterates over |ciphers| while |done| and |j| iterate over + * |ss->cipherSuites|. */ + unsigned int i, done; + + for (i = done = 0; i < len; i++) { + PRUint16 id = ciphers[i]; + unsigned int existingIndex, j; + PRBool found = PR_FALSE; + + for (j = done; j < ssl_V3_SUITES_IMPLEMENTED; j++) { + if (ss->cipherSuites[j].cipher_suite == id) { + existingIndex = j; + found = PR_TRUE; + break; + } + } + + if (!found) { + continue; + } + + if (existingIndex != done) { + const ssl3CipherSuiteCfg temp = ss->cipherSuites[done]; + ss->cipherSuites[done] = ss->cipherSuites[existingIndex]; + ss->cipherSuites[existingIndex] = temp; + } + done++; + } + + /* Disable all cipher suites that weren't included. */ + for (; done < ssl_V3_SUITES_IMPLEMENTED; done++) { + ss->cipherSuites[done].enabled = 0; + } + + return SECSuccess; +} + /* copy global default policy into socket. */ void ssl3_InitSocketPolicy(sslSocket *ss) diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h index 080debe..3403091 100644 --- a/lib/ssl/sslimpl.h +++ b/lib/ssl/sslimpl.h @@ -1786,6 +1786,8 @@ extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool extern SECStatus ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *on); extern SECStatus ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled); extern SECStatus ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled); +extern SECStatus ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *cipher, + unsigned int len); extern SECStatus ssl3_SetPolicy(ssl3CipherSuite which, PRInt32 policy); extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy); diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c index 28e3543..8ad1517 100644 --- a/lib/ssl/sslsock.c +++ b/lib/ssl/sslsock.c @@ -1369,6 +1369,19 @@ SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled) } SECStatus +SSL_CipherOrderSet(PRFileDesc *fd, const PRUint16 *ciphers, unsigned int len) +{ + sslSocket *ss = ssl_FindSocket(fd); + + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in CipherOrderSet", SSL_GETPID(), + fd)); + return SECFailure; + } + return ssl3_CipherOrderSet(ss, ciphers, len); +} + +SECStatus SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 which, PRBool *enabled) { SECStatus rv;