summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralexei.volkov.bugs%sun.com <devnull@localhost>2010-01-14 22:15:26 +0000
committeralexei.volkov.bugs%sun.com <devnull@localhost>2010-01-14 22:15:26 +0000
commit0888a1781a09700635e256bdd6c6380ab9ea1553 (patch)
tree9527a9f48931119e4855fe8b25d991ff51b7f0f8
parentf0fdc99bd9393b8ebc41ae6f68b7368fa0135bc0 (diff)
downloadnss-hg-0888a1781a09700635e256bdd6c6380ab9ea1553.tar.gz
360421 - Implement TLS Server Name Indication for servers. r=nelson
-rw-r--r--security/nss/cmd/selfserv/selfserv.c103
-rw-r--r--security/nss/cmd/tstclnt/tstclnt.c42
-rw-r--r--security/nss/lib/certdb/cert.h8
-rw-r--r--security/nss/lib/certhigh/certhigh.c95
-rw-r--r--security/nss/lib/nss/nss.def7
-rw-r--r--security/nss/lib/ssl/ssl.def10
-rw-r--r--security/nss/lib/ssl/ssl.h83
-rw-r--r--security/nss/lib/ssl/ssl3con.c227
-rw-r--r--security/nss/lib/ssl/ssl3ext.c184
-rw-r--r--security/nss/lib/ssl/sslimpl.h30
-rw-r--r--security/nss/lib/ssl/sslinfo.c38
-rw-r--r--security/nss/lib/ssl/sslreveal.c2
-rw-r--r--security/nss/lib/ssl/sslsecur.c203
-rw-r--r--security/nss/lib/ssl/sslsnce.c333
-rw-r--r--security/nss/lib/ssl/sslsock.c119
-rw-r--r--security/nss/lib/ssl/sslt.h5
-rwxr-xr-xsecurity/nss/tests/cert/cert.sh5
-rwxr-xr-xsecurity/nss/tests/ssl/ssl.sh19
-rw-r--r--security/nss/tests/ssl/sslauth.txt13
-rw-r--r--security/nss/tests/ssl/sslstress.txt2
20 files changed, 1341 insertions, 187 deletions
diff --git a/security/nss/cmd/selfserv/selfserv.c b/security/nss/cmd/selfserv/selfserv.c
index 4847990ee..f1b25ad5b 100644
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -176,6 +176,7 @@ Usage(const char *progName)
"Usage: %s -n rsa_nickname -p port [-3BDENRSTbjlmrsuvx] [-w password]\n"
" [-t threads] [-i pid_file] [-c ciphers] [-d dbdir] [-g numblocks]\n"
" [-f password_file] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
+" [-a sni_name]\n"
#ifdef NSS_ENABLE_ECC
" [-C SSLCacheEntries] [-e ec_nickname]\n"
#else
@@ -189,6 +190,7 @@ Usage(const char *progName)
"-D means disable Nagle delays in TCP\n"
"-E means disable export ciphersuites and SSL step down key gen\n"
"-R means disable detection of rollback from TLS to SSL3\n"
+"-a configure server for SNI.\n"
"-b means try binding to the port and exit\n"
"-m means test the model-socket feature of SSL_ImportFD.\n"
"-r flag is interepreted as follows:\n"
@@ -395,6 +397,18 @@ printSecurityInfo(PRFileDesc *fd)
channel.compressionMethodName);
}
}
+ if (verbose) {
+ SECItem *hostInfo = SSL_GetNegotiatedHostInfo(fd);
+ if (hostInfo) {
+ char namePref[] = "selfserv: Negotiated server name: ";
+
+ fprintf(stderr, "%s", namePref);
+ fwrite(hostInfo->data, hostInfo->len, 1, stderr);
+ SECITEM_FreeItem(hostInfo, PR_TRUE);
+ hostInfo = NULL;
+ fprintf(stderr, "\n");
+ }
+ }
if (requestCert)
cert = SSL_PeerCertificate(fd);
else
@@ -429,6 +443,71 @@ myBadCertHandler( void *arg, PRFileDesc *fd)
return (MakeCertOK ? SECSuccess : SECFailure);
}
+#define MAX_VIRT_SERVER_NAME_ARRAY_INDEX 10
+
+/* Simple SNI socket config function that does not use SSL_ReconfigFD.
+ * Only uses one server name but verifies that the names match. */
+PRInt32
+mySSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr,
+ PRUint32 sniNameArrSize, void *arg)
+{
+ PRInt32 i = 0;
+ const SECItem *current = sniNameArr;
+ const char **nameArr = (const char**)arg;
+ const secuPWData *pwdata;
+ CERTCertificate * cert = NULL;
+ SECKEYPrivateKey * privKey = NULL;
+
+ PORT_Assert(fd && sniNameArr);
+ if (!fd || !sniNameArr) {
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ pwdata = SSL_RevealPinArg(fd);
+
+ for (;current && i < sniNameArrSize;i++) {
+ int j = 0;
+ for (;j < MAX_VIRT_SERVER_NAME_ARRAY_INDEX && nameArr[j];j++) {
+ if (!PORT_Strncmp(nameArr[j],
+ (const char *)current[i].data,
+ current[i].len) &&
+ PORT_Strlen(nameArr[j]) == current[i].len) {
+ const char *nickName = nameArr[j];
+ if (j == 0) {
+ /* default cert */
+ return 0;
+ }
+ /* if pwdata is NULL, then we would not get the key and
+ * return an error status. */
+ cert = PK11_FindCertFromNickname(nickName, &pwdata);
+ if (cert == NULL) {
+ goto loser; /* Send alert */
+ }
+ privKey = PK11_FindKeyByAnyCert(cert, &pwdata);
+ if (privKey == NULL) {
+ goto loser; /* Send alert */
+ }
+ if (SSL_ConfigSecureServer(fd, cert, privKey,
+ kt_rsa) != SECSuccess) {
+ goto loser; /* Send alert */
+ }
+ SECKEY_DestroyPrivateKey(privKey);
+ CERT_DestroyCertificate(cert);
+ return i;
+ }
+ }
+ }
+loser:
+ if (privKey) {
+ SECKEY_DestroyPrivateKey(privKey);
+ }
+ if (cert) {
+ CERT_DestroyCertificate(cert);
+ }
+ return SSL_SNI_SEND_ALERT;
+}
+
+
/**************************************************************************
** Begin thread management routines and data.
**************************************************************************/
@@ -721,6 +800,7 @@ PRBool disableLocking = PR_FALSE;
PRBool testbypass = PR_FALSE;
PRBool enableSessionTickets = PR_FALSE;
PRBool enableCompression = PR_FALSE;
+static char *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX];
static const char stopCmd[] = { "GET /stop " };
static const char getCmd[] = { "GET " };
@@ -1610,6 +1690,12 @@ server_main(
}
}
+ rv = SSL_SNISocketConfigHook(model_sock, mySSLSNISocketConfig,
+ (void*)&virtServerNameArray);
+ if (rv != SECSuccess) {
+ errExit("error enabling SNI extension ");
+ }
+
for (kea = kt_rsa; kea < kt_kea_size; kea++) {
if (cert[kea] != NULL) {
secStatus = SSL_ConfigSecureServer(model_sock,
@@ -1829,6 +1915,7 @@ main(int argc, char **argv)
SSL3Statistics *ssl3stats;
PRUint32 i;
secuPWData pwdata = { PW_NONE, 0 };
+ int virtServerNameIndex = 1;
tmp = strrchr(argv[0], '/');
tmp = tmp ? tmp + 1 : argv[0];
@@ -1841,7 +1928,7 @@ main(int argc, char **argv)
** numbers, then capital letters, then lower case, alphabetical.
*/
optstate = PL_CreateOptState(argc, argv,
- "2:3BC:DEL:M:NP:RSTbc:d:e:f:g:hi:jlmn:op:qrst:uvw:xyz");
+ "2:3BC:DEL:M:NP:RSTa:bc:d:e:f:g:hi:jlmn:op:qrst:uvw:xyz");
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
++optionsFound;
switch(optstate->option) {
@@ -1880,6 +1967,12 @@ main(int argc, char **argv)
case 'T': disableTLS = PR_TRUE; break;
+ case 'a': if (virtServerNameIndex >= MAX_VIRT_SERVER_NAME_ARRAY_INDEX) {
+ Usage(progName);
+ }
+ virtServerNameArray[virtServerNameIndex++] =
+ PORT_Strdup(optstate->value); break;
+
case 'b': bindOnly = PR_TRUE; break;
case 'c': cipherString = PORT_Strdup(optstate->value); break;
@@ -1913,7 +2006,9 @@ main(int argc, char **argv)
case 'm': useModelSocket = PR_TRUE; break;
- case 'n': nickName = PORT_Strdup(optstate->value); break;
+ case 'n': nickName = PORT_Strdup(optstate->value);
+ virtServerNameArray[0] = PORT_Strdup(optstate->value);
+ break;
case 'P': certPrefix = PORT_Strdup(optstate->value); break;
@@ -2264,12 +2359,14 @@ cleanup:
SECKEY_DestroyPrivateKey(privKey[i]);
}
}
+ for (i = 0;virtServerNameArray[i];i++) {
+ PORT_Free(virtServerNameArray[i]);
+ }
}
if (debugCache) {
nss_DumpCertificateCacheInfo();
}
-
if (nickName) {
PORT_Free(nickName);
}
diff --git a/security/nss/cmd/tstclnt/tstclnt.c b/security/nss/cmd/tstclnt/tstclnt.c
index 080bb890c..54d6b9823 100644
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -181,6 +181,10 @@ void printSecurityInfo(PRFileDesc *fd)
void
handshakeCallback(PRFileDesc *fd, void *client_data)
{
+ const char *secondHandshakeName = (char *)client_data;
+ if (secondHandshakeName) {
+ SSL_SetURL(fd, secondHandshakeName);
+ }
printSecurityInfo(fd);
if (renegotiate > 0) {
renegotiate--;
@@ -191,8 +195,13 @@ handshakeCallback(PRFileDesc *fd, void *client_data)
static void Usage(const char *progName)
{
fprintf(stderr,
-"Usage: %s -h host [-p port] [-d certdir] [-n nickname] [-23BTfosvxr] \n"
-" [-c ciphers] [-w passwd] [-W pwfile] [-q]\n", progName);
+"Usage: %s -h host [-a 1st_hs_name ] [-a 2nd_hs_name ] [-p port]\n"
+ "[-d certdir] [-n nickname] [-23BTafosvxr] [-c ciphers]\n"
+ "[-w passwd] [-W pwfile] [-q]\n", progName);
+ fprintf(stderr, "%-20s Send different SNI name. 1st_hs_name - at first\n"
+ "%-20s handshake, 2nd_hs_name - at second handshake.\n"
+ "%-20s Defualt is host from the -h argument.\n", "-a name",
+ "", "");
fprintf(stderr, "%-20s Hostname to connect with\n", "-h host");
fprintf(stderr, "%-20s Port number for SSL server\n", "-p port");
fprintf(stderr,
@@ -521,6 +530,8 @@ int main(int argc, char **argv)
int headerSeparatorPtrnId = 0;
int error = 0;
PRUint16 portno = 443;
+ char * hs1SniHostName = NULL;
+ char * hs2SniHostName = NULL;
PLOptState *optstate;
PLOptStatus optstatus;
PRStatus prStatus;
@@ -539,7 +550,7 @@ int main(int argc, char **argv)
}
optstate = PL_CreateOptState(argc, argv,
- "23BSTW:c:d:fh:m:n:op:qr:suvw:xz");
+ "23BSTW:a:c:d:fh:m:n:op:qr:suvw:xz");
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
@@ -555,6 +566,15 @@ int main(int argc, char **argv)
case 'T': disableTLS = 1; break;
+ case 'a': if (!hs1SniHostName) {
+ hs1SniHostName = PORT_Strdup(optstate->value);
+ } else if (!hs2SniHostName) {
+ hs2SniHostName = PORT_Strdup(optstate->value);
+ } else {
+ Usage(progName);
+ }
+ break;
+
case 'c': cipherString = PORT_Strdup(optstate->value); break;
case 'd': certDir = PORT_Strdup(optstate->value); break;
@@ -842,7 +862,7 @@ int main(int argc, char **argv)
SECU_PrintError(progName, "error enabling compression");
return 1;
}
-
+
SSL_SetPKCS11PinArg(s, &pwdata);
SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle);
@@ -850,8 +870,12 @@ int main(int argc, char **argv)
SSL_BadCertHook(s, ownBadCertHandler, NULL);
}
SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
- SSL_HandshakeCallback(s, handshakeCallback, NULL);
- SSL_SetURL(s, host);
+ SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName);
+ if (hs1SniHostName) {
+ SSL_SetURL(s, hs1SniHostName);
+ } else {
+ SSL_SetURL(s, host);
+ }
/* Try to connect to the server */
status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
@@ -1059,6 +1083,12 @@ int main(int argc, char **argv)
}
done:
+ if (hs1SniHostName) {
+ PORT_Free(hs1SniHostName);
+ }
+ if (hs2SniHostName) {
+ PORT_Free(hs2SniHostName);
+ }
if (nickname) {
PORT_Free(nickname);
}
diff --git a/security/nss/lib/certdb/cert.h b/security/nss/lib/certdb/cert.h
index 7256306c1..47bf0d226 100644
--- a/security/nss/lib/certdb/cert.h
+++ b/security/nss/lib/certdb/cert.h
@@ -1077,6 +1077,9 @@ extern CERTDistNames *CERT_GetSSLCACerts(CERTCertDBHandle *handle);
extern void CERT_FreeDistNames(CERTDistNames *names);
+/* Duplicate distinguished name array */
+extern CERTDistNames *CERT_DupDistNames(CERTDistNames *orig);
+
/*
** Generate an array of Distinguished names from an array of nicknames
*/
@@ -1084,6 +1087,11 @@ extern CERTDistNames *CERT_DistNamesFromNicknames
(CERTCertDBHandle *handle, char **nicknames, int nnames);
/*
+** Generate an array of Distinguished names from a list of certs.
+*/
+extern CERTDistNames *CERT_DistNamesFromCertList(CERTCertList *list);
+
+/*
** Generate a certificate chain from a certificate.
*/
extern CERTCertificateList *
diff --git a/security/nss/lib/certhigh/certhigh.c b/security/nss/lib/certhigh/certhigh.c
index 6f4963f7e..83a4b01b2 100644
--- a/security/nss/lib/certhigh/certhigh.c
+++ b/security/nss/lib/certhigh/certhigh.c
@@ -618,6 +618,54 @@ CollectDistNames( CERTCertificate *cert, SECItem *k, void *data)
* Return all of the CAs that are "trusted" for SSL.
*/
CERTDistNames *
+CERT_DupDistNames(CERTDistNames *orig)
+{
+ PRArenaPool *arena;
+ CERTDistNames *names;
+ int i;
+ SECStatus rv;
+
+ /* allocate an arena to use */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return(NULL);
+ }
+
+ /* allocate the header structure */
+ names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
+ if (names == NULL) {
+ goto loser;
+ }
+
+ /* initialize the header struct */
+ names->arena = arena;
+ names->head = NULL;
+ names->nnames = orig->nnames;
+ names->names = NULL;
+
+ /* construct the array from the list */
+ if (orig->nnames) {
+ names->names = (SECItem*)PORT_ArenaNewArray(arena, SECItem,
+ orig->nnames);
+ if (names->names == NULL) {
+ goto loser;
+ }
+ for (i = 0; i < orig->nnames; i++) {
+ rv = SECITEM_CopyItem(arena, &names->names[i], &orig->names[i]);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ }
+ return(names);
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(NULL);
+}
+
+CERTDistNames *
CERT_GetSSLCACerts(CERTCertDBHandle *handle)
{
PRArenaPool *arena;
@@ -679,6 +727,53 @@ loser:
}
CERTDistNames *
+CERT_DistNamesFromCertList(CERTCertList *certList)
+{
+ CERTDistNames * dnames = NULL;
+ PRArenaPool * arena;
+ CERTCertListNode *node = NULL;
+ SECItem * names = NULL;
+ int listLen = 0, i = 0;
+
+ if (certList == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ node = CERT_LIST_HEAD(certList);
+ while ( ! CERT_LIST_END(node, certList) ) {
+ listLen += 1;
+ node = CERT_LIST_NEXT(node);
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) goto loser;
+ dnames = PORT_ArenaZNew(arena, CERTDistNames);
+ if (dnames == NULL) goto loser;
+
+ dnames->arena = arena;
+ dnames->nnames = listLen;
+ dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen);
+ if (names == NULL) goto loser;
+
+ node = CERT_LIST_HEAD(certList);
+ while ( ! CERT_LIST_END(node, certList) ) {
+ CERTCertificate *cert = node->cert;
+ SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject);
+ if (rv == SECFailure) {
+ goto loser;
+ }
+ node = CERT_LIST_NEXT(node);
+ }
+ return dnames;
+loser:
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ return NULL;
+}
+
+CERTDistNames *
CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames,
int nnames)
{
diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def
index e058e6f11..344715007 100644
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -989,3 +989,10 @@ SECMOD_GetSkipFirstFlag;
;+ local:
;+ *;
;+};
+;+NSS_3.12.6 { # NSS 3.12.6 release
+;+ global:
+CERT_DistNamesFromCertList;
+CERT_DupDistNames;
+;+ local:
+;+ *;
+;+};
diff --git a/security/nss/lib/ssl/ssl.def b/security/nss/lib/ssl/ssl.def
index e4d4d1dc0..200ba7d6d 100644
--- a/security/nss/lib/ssl/ssl.def
+++ b/security/nss/lib/ssl/ssl.def
@@ -139,3 +139,13 @@ SSL_CanBypass;
;+ local:
;+*;
;+};
+;+NSS_3.12.6 { # NSS 3.12.6 release
+;+ global:
+SSL_ConfigServerSessionIDCacheWithOpt;
+SSL_GetNegotiatedHostInfo;
+SSL_ReconfigFD;
+SSL_SetTrustAnchors;
+SSL_SNISocketConfigHook;
+;+ local:
+;+*;
+;+};
diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h
index 86b0aefe8..0d194e137 100644
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -270,6 +270,61 @@ SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd,
/*
+** SNI extension processing callback function.
+** It is called when SSL socket receives SNI extension in ClientHello message.
+** Upon this callback invocation, application is responsible to reconfigure the
+** socket with the data for a particular server name.
+** There are three potential outcomes of this function invocation:
+** * application does not recognize the name or the type and wants the
+** "unrecognized_name" alert be sent to the client. In this case the callback
+** function must return SSL_SNI_SEND_ALERT status.
+** * application does not recognize the name, but wants to continue with
+** the handshake using the current socket configuration. In this case,
+** no socket reconfiguration is needed and the function should return
+** SSL_SNI_CURRENT_CONFIG_IS_USED.
+** * application recognizes the name and reconfigures the socket with
+** appropriate certs, key, etc. There are many ways to reconfigure. NSS
+** provides SSL_ReconfigFD function that can be used to update the socket
+** data from model socket. To continue with the rest of the handshake, the
+** implementation function should return an index of a name it has chosen.
+** LibSSL will ignore any SNI extension received in a ClientHello message
+** if application does not register a SSLSNISocketConfig callback.
+** Each type field of SECItem indicates the name type.
+** NOTE: currently RFC3546 defines only one name type: sni_host_name.
+** Client is allowed to send only one name per known type. LibSSL will
+** send an "unrecognized_name" alert if SNI extension name list contains more
+** then one name of a type.
+*/
+typedef PRInt32 (PR_CALLBACK *SSLSNISocketConfig)(PRFileDesc *fd,
+ const SECItem *srvNameArr,
+ PRUint32 srvNameArrSize,
+ void *arg);
+
+/*
+** SSLSNISocketConfig should return an index within 0 and srvNameArrSize-1
+** when it has reconfigured the socket fd to use certs and keys, etc
+** for a specific name. There are two other allowed return values. One
+** tells libSSL to use the default cert and key. The other tells libSSL
+** to send the "unrecognized_name" alert. These values are:
+**/
+#define SSL_SNI_CURRENT_CONFIG_IS_USED -1
+#define SSL_SNI_SEND_ALERT -2
+
+/*
+** Set application implemented SNISocketConfig callback.
+*/
+SSL_IMPORT SECStatus SSL_SNISocketConfigHook(PRFileDesc *fd,
+ SSLSNISocketConfig f,
+ void *arg);
+
+/*
+** Reconfigure fd SSL socket with model socket parameters. Sets
+** server certs and keys, list of trust anchor, socket options
+** and all SSL socket call backs and parameters.
+*/
+SSL_IMPORT PRFileDesc *SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd);
+
+/*
* Set the client side argument for SSL to retrieve PKCS #11 pin.
* fd - the file descriptor for the connection in question
* a - pkcs11 application specific data
@@ -286,7 +341,7 @@ SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f,
void *arg);
/*
-** Configure ssl for running a secure server. Needs the
+** Configure SSL socket for running a secure server. Needs the
** certificate for the server and the servers private key. The arguments
** are copied.
*/
@@ -295,7 +350,7 @@ SSL_IMPORT SECStatus SSL_ConfigSecureServer(
SECKEYPrivateKey *key, SSLKEAType kea);
/*
-** Configure a secure servers session-id cache. Define the maximum number
+** Configure a secure server's session-id cache. Define the maximum number
** of entries in the cache, the longevity of the entires, and the directory
** where the cache files will be placed. These values can be zero, and
** if so, the implementation will choose defaults.
@@ -306,6 +361,18 @@ SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCache(int maxCacheEntries,
PRUint32 timeout,
PRUint32 ssl3_timeout,
const char * directory);
+
+/* Configure a secure server's session-id cache. Depends on value of
+ * enableMPCache, configures malti-proc or single proc cache. */
+SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCacheWithOpt(
+ PRUint32 timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory,
+ int maxCacheEntries,
+ int maxCertCacheEntries,
+ int maxSrvNameCacheEntries,
+ PRBool enableMPCache);
+
/*
** Like SSL_ConfigServerSessionIDCache, with one important difference.
** If the application will run multiple processes (as opposed to, or in
@@ -381,11 +448,17 @@ SSL_IMPORT SECStatus SSL_RedoHandshake(PRFileDesc *fd);
#endif
/*
- * Allow the application to pass a URL or hostname into the SSL library
+ * Allow the application to pass a URL or hostname into the SSL library.
*/
SSL_IMPORT SECStatus SSL_SetURL(PRFileDesc *fd, const char *url);
/*
+ * Allow an application to define a set of trust anchors for peer
+ * cert validation.
+ */
+SSL_IMPORT SECStatus SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *list);
+
+/*
** Return the number of bytes that SSL has waiting in internal buffers.
** Return 0 if security is not enabled.
*/
@@ -424,7 +497,6 @@ SSL_IMPORT CERTCertificate * SSL_RevealCert(PRFileDesc * socket);
SSL_IMPORT void * SSL_RevealPinArg(PRFileDesc * socket);
SSL_IMPORT char * SSL_RevealURL(PRFileDesc * socket);
-
/* This callback may be passed to the SSL library via a call to
* SSL_GetClientAuthDataHook() for each SSL client socket.
* It will be invoked when SSL needs to know what certificate and private key
@@ -487,6 +559,9 @@ SSL_IMPORT SECStatus SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info,
SSL_IMPORT SECStatus SSL_GetCipherSuiteInfo(PRUint16 cipherSuite,
SSLCipherSuiteInfo *info, PRUintn len);
+/* Returnes negotiated through SNI host info. */
+SSL_IMPORT SECItem *SSL_GetNegotiatedHostInfo(PRFileDesc *fd);
+
/*
** Return a new reference to the certificate that was most recently sent
** to the peer on this SSL/TLS connection, or NULL if none has been sent.
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 25157fe29..bd3df17e6 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1168,7 +1168,7 @@ ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat)
** Caller must hold SpecWriteLock.
*/
static void
-ssl3_DestroyCipherSpec(ssl3CipherSpec *spec)
+ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName)
{
PRBool freeit = (PRBool)(!spec->bypassCiphers);
/* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */
@@ -1186,6 +1186,9 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *spec)
spec->destroyDecompressContext(spec->decompressContext, 1);
spec->decompressContext = NULL;
}
+ if (freeSrvName && spec->srvVirtName.data) {
+ SECITEM_FreeItem(&spec->srvVirtName, PR_FALSE);
+ }
if (spec->master_secret != NULL) {
PK11_FreeSymKey(spec->master_secret);
spec->master_secret = NULL;
@@ -1444,8 +1447,8 @@ const ssl3BulkCipherDef *cipher_def;
SSLCompressionMethod compression_method;
SECStatus rv;
- PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
pwSpec = ss->ssl3.pwSpec;
@@ -1557,6 +1560,14 @@ const ssl3BulkCipherDef *cipher_def;
* is decrypting, and vice versa.
*/
optArg1 = !optArg1;
+ break;
+ /* kill warnings. */
+ case ssl_calg_null:
+ case ssl_calg_rc4:
+ case ssl_calg_rc2:
+ case ssl_calg_idea:
+ case ssl_calg_fortezza:
+ break;
}
rv = (*initFn)(clientContext,
@@ -1625,7 +1636,7 @@ const ssl3BulkCipherDef *cipher_def;
SSLCipherAlgorithm calg;
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
pwSpec = ss->ssl3.pwSpec;
@@ -2722,7 +2733,7 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss)
* (Both the read and write sides have changed) destroy it.
*/
if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
- ssl3_DestroyCipherSpec(ss->ssl3.pwSpec);
+ ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE/*freeSrvName*/);
}
ssl_ReleaseSpecWriteLock(ss); /**************************************/
@@ -2784,7 +2795,7 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf)
* (Both the read and write sides have changed) destroy it.
*/
if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
- ssl3_DestroyCipherSpec(ss->ssl3.prSpec);
+ ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE/*freeSrvName*/);
}
ssl_ReleaseSpecWriteLock(ss); /*************************************/
return SECSuccess;
@@ -5672,6 +5683,25 @@ ssl3_SendHelloRequest(sslSocket *ss)
return SECSuccess;
}
+/*
+ * Called from:
+ * ssl3_HandleClientHello()
+ */
+static SECComparison
+ssl3_ServerNameCompare(const SECItem *name1, const SECItem *name2)
+{
+ if (!name1 != !name2) {
+ return SECLessThan;
+ }
+ if (!name1) {
+ return SECEqual;
+ }
+ if (name1->type != name2->type) {
+ return SECLessThan;
+ }
+ return SECITEM_CompareItem(name1, name2);
+}
+
/* Sets memory error when returning NULL.
* Called from:
* ssl3_SendClientHello()
@@ -5688,6 +5718,21 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
if (sid == NULL)
return sid;
+ if (is_server) {
+ const SECItem * srvName;
+ SECStatus rv = SECSuccess;
+
+ ssl_GetSpecReadLock(ss); /********************************/
+ srvName = &ss->ssl3.prSpec->srvVirtName;
+ if (srvName->len && srvName->data) {
+ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName, srvName);
+ }
+ ssl_ReleaseSpecReadLock(ss); /************************************/
+ if (rv != SECSuccess) {
+ PORT_Free(sid);
+ return NULL;
+ }
+ }
sid->peerID = (ss->peerID == NULL) ? NULL : PORT_Strdup(ss->peerID);
sid->urlSvrName = (ss->url == NULL) ? NULL : PORT_Strdup(ss->url);
sid->addr = ss->sec.ci.peer;
@@ -6225,6 +6270,32 @@ compression_found:
ss->sec.localCert =
CERT_DupCertificate(ss->serverCerts[sid->keaType].serverCert);
+ /* Copy cached name in to pending spec */
+ if (sid != NULL &&
+ sid->version > SSL_LIBRARY_VERSION_3_0 &&
+ sid->u.ssl3.srvName.len && sid->u.ssl3.srvName.data) {
+ /* Set server name from sid */
+ SECItem *sidName = &sid->u.ssl3.srvName;
+ SECItem *pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ rv = SECITEM_CopyItem(NULL, pwsName, sidName);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ desc = internal_error;
+ goto alert_loser;
+ }
+ }
+
+ /* Clean up sni name array */
+ if (ssl3_ExtensionNegotiated(ss, server_name_xtn) &&
+ ss->xtnData.sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ ss->xtnData.sniNameArr = NULL;
+ ss->xtnData.sniNameArrSize = 0;
+ }
+
ssl_GetXmitBufLock(ss); haveXmitBufLock = PR_TRUE;
rv = ssl3_SendServerHello(ss);
@@ -6278,6 +6349,146 @@ compression_found:
}
SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses );
+ if (ssl3_ExtensionNegotiated(ss, server_name_xtn)) {
+ int ret = 0;
+ if (ss->sniSocketConfig) do { /* not a loop */
+ ret = SSL_SNI_SEND_ALERT;
+ /* If extension is negotiated, the len of names should > 0. */
+ if (ss->xtnData.sniNameArrSize) {
+ /* Calling client callback to reconfigure the socket. */
+ ret = (SECStatus)(*ss->sniSocketConfig)(ss->fd,
+ ss->xtnData.sniNameArr,
+ ss->xtnData.sniNameArrSize,
+ ss->sniSocketConfigArg);
+ }
+ if (ret <= SSL_SNI_SEND_ALERT) {
+ /* Application does not know the name or was not able to
+ * properly reconfigure the socket. */
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = unrecognized_name;
+ break;
+ } else if (ret == SSL_SNI_CURRENT_CONFIG_IS_USED) {
+ SECStatus rv = SECSuccess;
+ SECItem * cwsName, *pwsName;
+
+ ssl_GetSpecWriteLock(ss); /*******************************/
+ pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ cwsName = &ss->ssl3.cwSpec->srvVirtName;
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ /* not allow name change on the 2d HS */
+ if (ss->firstHsDone) {
+ if (ssl3_ServerNameCompare(pwsName, cwsName)) {
+ ssl_ReleaseSpecWriteLock(ss); /******************/
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ }
+#endif
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ if (cwsName->data) {
+ rv = SECITEM_CopyItem(NULL, pwsName, cwsName);
+ }
+ ssl_ReleaseSpecWriteLock(ss); /**************************/
+ if (rv != SECSuccess) {
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ } else if (ret < ss->xtnData.sniNameArrSize) {
+ /* Application has configured new socket info. Lets check it
+ * and save the name. */
+ SECStatus rv;
+ SECItem * name = &ss->xtnData.sniNameArr[ret];
+ int configedCiphers;
+ SECItem * pwsName;
+
+ /* get rid of the old name and save the newly picked. */
+ /* This code is protected by ssl3HandshakeLock. */
+ ssl_GetSpecWriteLock(ss); /*******************************/
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ /* not allow name change on the 2d HS */
+ if (ss->firstHsDone) {
+ SECItem *cwsName = &ss->ssl3.cwSpec->srvVirtName;
+ if (ssl3_ServerNameCompare(name, cwsName)) {
+ ssl_ReleaseSpecWriteLock(ss); /******************/
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ }
+#endif
+ pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ rv = SECITEM_CopyItem(NULL, pwsName, name);
+ ssl_ReleaseSpecWriteLock(ss); /***************************/
+ if (rv != SECSuccess) {
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ configedCiphers = ssl3_config_match_init(ss);
+ if (configedCiphers <= 0) {
+ /* no ciphers are working/supported */
+ errCode = PORT_GetError();
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ /* Need to tell the client that application has picked
+ * the name from the offered list and reconfigured the socket.
+ */
+ ssl3_RegisterServerHelloExtensionSender(ss, server_name_xtn,
+ ssl3_SendServerNameXtn);
+ } else {
+ /* Callback returned index outside of the boundary. */
+ PORT_Assert(ret < ss->xtnData.sniNameArrSize);
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ } while (0);
+ /* Free sniNameArr. The data that each SECItem in the array
+ * points into is the data from the input buffer "b". It will
+ * not be available outside the scope of this or it's child
+ * functions.*/
+ if (ss->xtnData.sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ ss->xtnData.sniNameArr = NULL;
+ ss->xtnData.sniNameArrSize = 0;
+ }
+ if (ret <= SSL_SNI_SEND_ALERT) {
+ /* desc and errCode should be set. */
+ goto alert_loser;
+ }
+ }
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ else if (ss->firstHsDone) {
+ /* Check that we don't have the name is current spec
+ * if this extension was not negotiated on the 2d hs. */
+ PRBool passed = PR_TRUE;
+ ssl_GetSpecReadLock(ss); /*******************************/
+ if (ss->ssl3.cwSpec->srvVirtName.data) {
+ passed = PR_FALSE;
+ }
+ ssl_ReleaseSpecReadLock(ss); /***************************/
+ if (!passed) {
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ goto alert_loser;
+ }
+ }
+#endif
+
sid = ssl3_NewSessionID(ss, PR_TRUE);
if (sid == NULL) {
errCode = PORT_GetError();
@@ -9069,8 +9280,8 @@ ssl3_DestroySSL3Info(sslSocket *ss)
PORT_Free(ss->ssl3.hs.msg_body.buf);
/* free up the CipherSpecs */
- ssl3_DestroyCipherSpec(&ss->ssl3.specs[0]);
- ssl3_DestroyCipherSpec(&ss->ssl3.specs[1]);
+ ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE/*freeSrvName*/);
+ ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/);
ss->ssl3.initialized = PR_FALSE;
}
diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c
index d5a7a3b44..c075510fd 100644
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -61,8 +61,6 @@ static unsigned char session_ticket_mac_key[SHA256_LENGTH];
static PRBool session_ticket_keys_initialized = PR_FALSE;
static PRCallOnceType generate_session_keys_once;
-static PRInt32 ssl3_SendServerNameXtn(sslSocket * ss,
- PRBool append, PRUint32 maxBytes);
static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss,
SECItem *data, EncryptedSessionTicket *enc_session_ticket);
static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf,
@@ -284,60 +282,158 @@ ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type) {
/* Format an SNI extension, using the name from the socket's URL,
* unless that name is a dotted decimal string.
+ * Used by client and server.
*/
-static PRInt32
-ssl3_SendServerNameXtn(
- sslSocket * ss,
- PRBool append,
- PRUint32 maxBytes)
+PRInt32
+ssl3_SendServerNameXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes)
{
- PRUint32 len;
- PRNetAddr netAddr;
-
- /* must have a hostname */
- if (!ss || !ss->url || !ss->url[0])
- return 0;
- /* must not be an IPv4 or IPv6 address */
- if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) {
- /* is an IP address (v4 or v6) */
- return 0;
+ SECStatus rv;
+ if (!ss->sec.isServer) {
+ PRUint32 len;
+ PRNetAddr netAddr;
+
+ /* must have a hostname */
+ if (!ss || !ss->url || !ss->url[0])
+ return 0;
+ /* must not be an IPv4 or IPv6 address */
+ if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) {
+ /* is an IP address (v4 or v6) */
+ return 0;
+ }
+ len = PORT_Strlen(ss->url);
+ if (append && maxBytes >= len + 9) {
+ /* extension_type */
+ rv = ssl3_AppendHandshakeNumber(ss, server_name_xtn, 2);
+ if (rv != SECSuccess) return -1;
+ /* length of extension_data */
+ rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2);
+ if (rv != SECSuccess) return -1;
+ /* length of server_name_list */
+ rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2);
+ if (rv != SECSuccess) return -1;
+ /* Name Type (sni_host_name) */
+ rv = ssl3_AppendHandshake(ss, "\0", 1);
+ if (rv != SECSuccess) return -1;
+ /* HostName (length and value) */
+ rv = ssl3_AppendHandshakeVariable(ss, (unsigned char *)ss->url, len, 2);
+ if (rv != SECSuccess) return -1;
+ if (!ss->sec.isServer) {
+ TLSExtensionData *xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] = server_name_xtn;
+ }
+ }
+ return len + 9;
}
- len = PORT_Strlen(ss->url);
- if (append && maxBytes >= len + 9) {
- SECStatus rv;
- /* extension_type */
- rv = ssl3_AppendHandshakeNumber(ss, server_name_xtn, 2);
- if (rv != SECSuccess) return -1;
- /* length of extension_data */
- rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2);
- if (rv != SECSuccess) return -1;
- /* length of server_name_list */
- rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2);
- if (rv != SECSuccess) return -1;
- /* Name Type (host_name) */
- rv = ssl3_AppendHandshake(ss, "\0", 1);
- if (rv != SECSuccess) return -1;
- /* HostName (length and value) */
- rv = ssl3_AppendHandshakeVariable(ss, (unsigned char *)ss->url, len, 2);
- if (rv != SECSuccess) return -1;
- if (!ss->sec.isServer) {
- TLSExtensionData *xtnData = &ss->xtnData;
- xtnData->advertised[xtnData->numAdvertised++] = server_name_xtn;
- }
+ /* Server side */
+ if (append && maxBytes >= 4) {
+ rv = ssl3_AppendHandshakeNumber(ss, server_name_xtn, 2);
+ if (rv != SECSuccess) return -1;
+ /* length of extension_data */
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess) return -1;
}
- return len + 9;
+ return 4;
}
/* handle an incoming SNI extension, by ignoring it. */
SECStatus
ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
{
- /* TODO: if client, should verify extension_data is empty. */
- /* TODO: if server, should send empty extension_data. */
- /* For now, we ignore this, as if we didn't understand it. :-) */
+ SECItem *names = NULL;
+ PRUint32 listCount = 0, namesPos = 0, i;
+ TLSExtensionData *xtnData = &ss->xtnData;
+ SECItem ldata;
+ PRInt32 listLenBytes = 0;
+
+ if (!ss->sec.isServer) {
+ /* Verify extension_data is empty. */
+ if (data->data || data->len ||
+ !ssl3_ExtensionNegotiated(ss, server_name_xtn)) {
+ /* malformed or was not initiated by the client.*/
+ return SECFailure;
+ }
+ return SECSuccess;
+ }
+
+ /* Server side - consume client data and register server sender. */
+ /* do not parse the data if don't have user extension handling function. */
+ if (!ss->sniSocketConfig) {
+ return SECSuccess;
+ }
+ /* length of server_name_list */
+ listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+ if (listLenBytes == 0 || listLenBytes != data->len) {
+ return SECFailure;
+ }
+ ldata = *data;
+ /* Calculate the size of the array.*/
+ while (listLenBytes > 0) {
+ SECItem litem;
+ SECStatus rv;
+ PRInt32 type;
+ /* Name Type (sni_host_name) */
+ type = ssl3_ConsumeHandshakeNumber(ss, 1, &ldata.data, &ldata.len);
+ if (!ldata.len) {
+ return SECFailure;
+ }
+ rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 2, &ldata.data, &ldata.len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ /* Adjust total length for cunsumed item, item len and type.*/
+ listLenBytes -= litem.len + 3;
+ if (listLenBytes > 0 && !ldata.len) {
+ return SECFailure;
+ }
+ listCount += 1;
+ }
+ if (!listCount) {
+ return SECFailure;
+ }
+ names = PORT_ZNewArray(SECItem, listCount);
+ if (!names) {
+ return SECFailure;
+ }
+ for (i = 0;i < listCount;i++) {
+ int j;
+ PRInt32 type;
+ SECStatus rv;
+ PRBool nametypePresent = PR_FALSE;
+ /* Name Type (sni_host_name) */
+ type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
+ /* Check if we have such type in the list */
+ for (j = 0;j < listCount && names[j].data;j++) {
+ if (names[j].type == type) {
+ nametypePresent = PR_TRUE;
+ break;
+ }
+ }
+ /* HostName (length and value) */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &names[namesPos], 2,
+ &data->data, &data->len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (nametypePresent == PR_FALSE) {
+ namesPos += 1;
+ }
+ }
+ /* Free old and set the new data. */
+ if (xtnData->sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ }
+ xtnData->sniNameArr = names;
+ xtnData->sniNameArrSize = namesPos;
+ xtnData->negotiated[xtnData->numNegotiated++] = server_name_xtn;
+
return SECSuccess;
-}
+loser:
+ PORT_Free(names);
+ return SECFailure;
+}
+
/* Called by both clients and servers.
* Clients sends a filled in session ticket if one is available, and otherwise
* sends an empty ticket. Servers always send empty tickets.
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index 9ed107eb5..cbfd60999 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -556,6 +556,9 @@ typedef struct {
SECItem msItem;
unsigned char key_block[NUM_MIXERS * MD5_LENGTH];
unsigned char raw_master_secret[56];
+ SECItem srvVirtName; /* for server: name that was negotiated
+ * with a client. For client - is
+ * always set to NULL.*/
} ssl3CipherSpec;
typedef enum { never_cached,
@@ -651,6 +654,7 @@ struct sslSessionIDStr {
* ClientHello message. This field is used by clients.
*/
NewSessionTicket sessionTicket;
+ SECItem srvName;
} ssl3;
} u;
};
@@ -735,6 +739,13 @@ struct TLSExtensionDataStr {
/* SessionTicket Extension related data. */
PRBool ticketTimestampVerified;
PRBool emptySessionTicket;
+
+ /* SNI Extension related data
+ * Names data is not coppied from the input buffer. It can not be
+ * used outside the scope where input buffer is defined and that
+ * is beyond ssl3_HandleClientHello function. */
+ SECItem *sniNameArr;
+ PRUint32 sniNameArrSize;
};
/*
@@ -1034,6 +1045,8 @@ const unsigned char * preferredCipher;
void *authCertificateArg;
SSLGetClientAuthData getClientAuthData;
void *getClientAuthDataArg;
+ SSLSNISocketConfig sniSocketConfig;
+ void *sniSocketConfigArg;
SSLBadCertHandler handleBadCert;
void *badCertArg;
SSLHandshakeCallback handshakeCallback;
@@ -1481,6 +1494,23 @@ extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss,
*/
extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
+
+/* ClientHello and ServerHello extension senders.
+ * The code is in ssl3ext.c.
+ */
+extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+
+/* Assigns new cert, cert chain and keys to ss->serverCerts
+ * struct. If certChain is NULL, tries to find one. Aborts if
+ * fails to do so. If cert and keyPair are NULL - unconfigures
+ * sslSocket of kea type.*/
+extern SECStatus ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert,
+ CERTCertificateList *certChain,
+ ssl3KeyPair *keyPair, SSLKEAType kea);
+/* Return key type for the cert */
+extern SSLKEAType ssl_FindCertKEAType(CERTCertificate * cert);
+
#ifdef NSS_ENABLE_ECC
extern PRInt32 ssl3_SendSupportedCurvesXtn(sslSocket *ss,
PRBool append, PRUint32 maxBytes);
diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c
index 12bcac4cf..e5d4fa699 100644
--- a/security/nss/lib/ssl/sslinfo.c
+++ b/security/nss/lib/ssl/sslinfo.c
@@ -307,3 +307,41 @@ SSL_IsExportCipherSuite(PRUint16 cipherSuite)
}
return PR_FALSE;
}
+
+SECItem*
+SSL_GetNegotiatedHostInfo(PRFileDesc *fd)
+{
+ SECItem *sniName = NULL;
+ sslSocket *ss;
+ char *name = NULL;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNegotiatedHostInfo",
+ SSL_GETPID(), fd));
+ return NULL;
+ }
+
+ if (ss->sec.isServer) {
+ SECItem *crsName;
+
+ ssl_GetSpecReadLock(ss); /*********************************/
+ crsName = &ss->ssl3.crSpec->srvVirtName;
+ if (crsName->data) {
+ sniName = SECITEM_DupItem(crsName);
+ }
+ ssl_ReleaseSpecReadLock(ss); /*----------------------------*/
+ return sniName;
+ }
+ name = SSL_RevealURL(fd);
+ if (name) {
+ sniName = PORT_ZNew(SECItem);
+ if (!sniName) {
+ PORT_Free(name);
+ return NULL;
+ }
+ sniName->data = (void*)name;
+ sniName->len = PORT_Strlen(name);
+ }
+ return sniName;
+}
diff --git a/security/nss/lib/ssl/sslreveal.c b/security/nss/lib/ssl/sslreveal.c
index 09d20d496..b713b0ef9 100644
--- a/security/nss/lib/ssl/sslreveal.c
+++ b/security/nss/lib/ssl/sslreveal.c
@@ -82,7 +82,7 @@ SSL_RevealPinArg(PRFileDesc * fd)
/* given PRFileDesc, returns a pointer to the URL associated with the socket
- * the caller should free url when done
+ * the caller should free url when done
*/
char *
SSL_RevealURL(PRFileDesc * fd)
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index c2bbadbc2..fc2c73dd9 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -672,6 +672,79 @@ static PRStatus serverCAListSetup(void *arg)
return PR_FAILURE;
}
+SECStatus
+ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert,
+ CERTCertificateList *certChain,
+ ssl3KeyPair *keyPair, SSLKEAType kea)
+{
+ CERTCertificateList *localCertChain = NULL;
+ sslServerCerts *sc = ss->serverCerts + kea;
+
+ /* load the server certificate */
+ if (sc->serverCert != NULL) {
+ CERT_DestroyCertificate(sc->serverCert);
+ sc->serverCert = NULL;
+ sc->serverKeyBits = 0;
+ }
+ /* load the server cert chain */
+ if (sc->serverCertChain != NULL) {
+ CERT_DestroyCertificateList(sc->serverCertChain);
+ sc->serverCertChain = NULL;
+ }
+ if (cert) {
+ sc->serverCert = CERT_DupCertificate(cert);
+ /* get the size of the cert's public key, and remember it */
+ sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
+ if (!certChain) {
+ localCertChain =
+ CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer,
+ PR_TRUE);
+ if (!localCertChain)
+ goto loser;
+ }
+ sc->serverCertChain = (certChain) ? CERT_DupCertList(certChain) :
+ localCertChain;
+ if (!sc->serverCertChain) {
+ goto loser;
+ }
+ localCertChain = NULL; /* consumed */
+ }
+
+ /* get keyPair */
+ if (sc->serverKeyPair != NULL) {
+ ssl3_FreeKeyPair(sc->serverKeyPair);
+ sc->serverKeyPair = NULL;
+ }
+ if (keyPair) {
+ SECKEY_CacheStaticFlags(keyPair->privKey);
+ sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair);
+ }
+ if (kea == kt_rsa && cert && sc->serverKeyBits > 512 &&
+ !ss->opt.noStepDown && !ss->stepDownKeyPair) {
+ if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) {
+ goto loser;
+ }
+ }
+ return SECSuccess;
+
+loser:
+ if (localCertChain) {
+ CERT_DestroyCertificateList(localCertChain);
+ }
+ if (sc->serverCert != NULL) {
+ CERT_DestroyCertificate(sc->serverCert);
+ sc->serverCert = NULL;
+ }
+ if (sc->serverCertChain != NULL) {
+ CERT_DestroyCertificateList(sc->serverCertChain);
+ sc->serverCertChain = NULL;
+ }
+ if (sc->serverKeyPair != NULL) {
+ ssl3_FreeKeyPair(sc->serverKeyPair);
+ sc->serverKeyPair = NULL;
+ }
+ return SECFailure;
+}
/* XXX need to protect the data that gets changed here.!! */
@@ -679,10 +752,10 @@ SECStatus
SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
SECKEYPrivateKey *key, SSL3KEAType kea)
{
- SECStatus rv;
sslSocket *ss;
- sslServerCerts *sc;
- SECKEYPublicKey * pubKey = NULL;
+ SECKEYPublicKey *pubKey = NULL;
+ ssl3KeyPair *keyPair = NULL;
+ SECStatus rv = SECFailure;
ss = ssl_FindSocket(fd);
if (!ss) {
@@ -708,41 +781,13 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
return SECFailure;
}
- sc = ss->serverCerts + kea;
- /* load the server certificate */
- if (sc->serverCert != NULL) {
- CERT_DestroyCertificate(sc->serverCert);
- sc->serverCert = NULL;
- }
if (cert) {
- sc->serverCert = CERT_DupCertificate(cert);
- if (!sc->serverCert)
- goto loser;
/* get the size of the cert's public key, and remember it */
pubKey = CERT_ExtractPublicKey(cert);
if (!pubKey)
- goto loser;
- sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey);
- }
-
-
- /* load the server cert chain */
- if (sc->serverCertChain != NULL) {
- CERT_DestroyCertificateList(sc->serverCertChain);
- sc->serverCertChain = NULL;
- }
- if (cert) {
- sc->serverCertChain = CERT_CertChainFromCert(
- sc->serverCert, certUsageSSLServer, PR_TRUE);
- if (sc->serverCertChain == NULL)
- goto loser;
+ return SECFailure;
}
- /* load the private key */
- if (sc->serverKeyPair != NULL) {
- ssl3_FreeKeyPair(sc->serverKeyPair);
- sc->serverKeyPair = NULL;
- }
if (key) {
SECKEYPrivateKey * keyCopy = NULL;
CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM;
@@ -770,51 +815,34 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
keyCopy = SECKEY_CopyPrivateKey(key);
if (keyCopy == NULL)
goto loser;
- SECKEY_CacheStaticFlags(keyCopy);
- sc->serverKeyPair = ssl3_NewKeyPair(keyCopy, pubKey);
- if (sc->serverKeyPair == NULL) {
+ keyPair = ssl3_NewKeyPair(keyCopy, pubKey);
+ if (keyPair == NULL) {
SECKEY_DestroyPrivateKey(keyCopy);
goto loser;
}
pubKey = NULL; /* adopted by serverKeyPair */
}
-
- if (kea == kt_rsa && cert && sc->serverKeyBits > 512) {
- if (ss->opt.noStepDown) {
- /* disable all export ciphersuites */
- } else {
- rv = ssl3_CreateRSAStepDownKeys(ss);
- if (rv != SECSuccess) {
- return SECFailure; /* err set by ssl3_CreateRSAStepDownKeys */
- }
- }
+ if (ssl_ConfigSecureServer(ss, cert, NULL,
+ keyPair, kea) == SECFailure) {
+ goto loser;
}
/* Only do this once because it's global. */
if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce,
&serverCAListSetup,
(void *)(ss->dbHandle))) {
- return SECSuccess;
+ rv = SECSuccess;
}
loser:
+ if (keyPair) {
+ ssl3_FreeKeyPair(keyPair);
+ }
if (pubKey) {
SECKEY_DestroyPublicKey(pubKey);
pubKey = NULL;
}
- if (sc->serverCert != NULL) {
- CERT_DestroyCertificate(sc->serverCert);
- sc->serverCert = NULL;
- }
- if (sc->serverCertChain != NULL) {
- CERT_DestroyCertificateList(sc->serverCertChain);
- sc->serverCertChain = NULL;
- }
- if (sc->serverKeyPair != NULL) {
- ssl3_FreeKeyPair(sc->serverKeyPair);
- sc->serverKeyPair = NULL;
- }
- return SECFailure;
+ return rv;
}
/************************************************************************/
@@ -1241,7 +1269,8 @@ SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg)
/*
* Allow the application to pass the url or hostname into the SSL library
- * so that we can do some checking on it.
+ * so that we can do some checking on it. It will be used for the value in
+ * SNI extension of client hello message.
*/
SECStatus
SSL_SetURL(PRFileDesc *fd, const char *url)
@@ -1273,6 +1302,41 @@ SSL_SetURL(PRFileDesc *fd, const char *url)
}
/*
+ * Allow the application to pass the set of trust anchors
+ */
+SECStatus
+SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList)
+{
+ sslSocket * ss = ssl_FindSocket(fd);
+ CERTDistNames *names = NULL;
+
+ if (!certList) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTrustAnchors",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ names = CERT_DistNamesFromCertList(certList);
+ if (names == NULL) {
+ return SECFailure;
+ }
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ if (ss->ssl3.ca_list) {
+ CERT_FreeDistNames(ss->ssl3.ca_list);
+ }
+ ss->ssl3.ca_list = names;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECSuccess;
+}
+
+/*
** Returns Negative number on error, zero or greater on success.
** Returns the amount of data immediately available to be read.
*/
@@ -1440,3 +1504,22 @@ SSL_RestartHandshakeAfterServerCert(sslSocket *ss)
ssl_Release1stHandshakeLock(ss);
return rv;
}
+
+/* For more info see ssl.h */
+SECStatus
+SSL_SNISocketConfigHook(PRFileDesc *fd, SSLSNISocketConfig func,
+ void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SNISocketConfigHook",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ss->sniSocketConfig = func;
+ ss->sniSocketConfigArg = arg;
+ return SECSuccess;
+}
diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c
index 6b167458e..45deb493f 100644
--- a/security/nss/lib/ssl/sslsnce.c
+++ b/security/nss/lib/ssl/sslsnce.c
@@ -71,6 +71,8 @@
* encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode
* encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode
* PRBool ticketKeysValid;
+ * sidCacheLock srvNameCacheLock;
+ * srvNameCacheEntry srvNameData[ numSrvNameCacheEntries ];
* } cacheMemCacheData;
*/
#include "seccomon.h"
@@ -84,6 +86,7 @@
#include "pk11func.h"
#include "base64.h"
#include "keyhi.h"
+#include "blapi.h"
#include <stdio.h>
@@ -150,10 +153,12 @@ struct sidCacheEntryStr {
/* 4 */ PRUint32 masterWrapMech;
/* 4 */ SSL3KEAType exchKeyType;
/* 4 */ PRInt32 certIndex;
-/*116 */} ssl3;
+/* 4 */ PRInt32 srvNameIndex;
+/* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
+/*152 */} ssl3;
/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
struct {
-/*120 */ PRUint8 filler[120]; /* 72+120==196, a multiple of 16 */
+/*152 */ PRUint8 filler[120]; /* 72+152==224, a multiple of 16 */
} forceSize;
} u;
};
@@ -186,6 +191,18 @@ struct encKeyCacheEntryStr {
};
typedef struct encKeyCacheEntryStr encKeyCacheEntry;
+#define SSL_MAX_DNS_HOST_NAME 1024
+
+struct srvNameCacheEntryStr {
+ PRUint16 type; /* 2 */
+ PRUint16 nameLen; /* 2 */
+ PRUint8 name[SSL_MAX_DNS_HOST_NAME + 12]; /* 1034 */
+ PRUint8 nameHash[SHA256_LENGTH]; /* 32 */
+ /* 1072 */
+};
+typedef struct srvNameCacheEntryStr srvNameCacheEntry;
+
+
struct cacheDescStr {
PRUint32 cacheMemSize;
@@ -203,6 +220,9 @@ struct cacheDescStr {
PRUint32 numKeyCacheEntries;
PRUint32 keyCacheSize;
+ PRUint32 numSrvNameCacheEntries;
+ PRUint32 srvNameCacheSize;
+
PRUint32 ssl2Timeout;
PRUint32 ssl3Timeout;
@@ -218,6 +238,7 @@ struct cacheDescStr {
sidCacheLock * sidCacheLocks;
sidCacheLock * keyCacheLock;
sidCacheLock * certCacheLock;
+ sidCacheLock * srvNameCacheLock;
sidCacheSet * sidCacheSets;
sidCacheEntry * sidCacheData;
certCacheEntry * certCacheData;
@@ -226,6 +247,7 @@ struct cacheDescStr {
encKeyCacheEntry * ticketEncKey;
encKeyCacheEntry * ticketMacKey;
PRUint32 * ticketKeysValid;
+ srvNameCacheEntry * srvNameCacheData;
/* Only the private copies of these pointers are valid */
char * cacheMem;
@@ -248,6 +270,7 @@ static PRBool isMultiProcess = PR_FALSE;
#define DEF_CERT_CACHE_ENTRIES 250
#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
#define DEF_KEY_CACHE_ENTRIES 250
+#define DEF_NAME_CACHE_ENTRIES 1000
#define SID_CACHE_ENTRIES_PER_SET 128
#define SID_ALIGNMENT 16
@@ -394,6 +417,59 @@ CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
}
+/* Server configuration hash tables need to account the SECITEM.type
+ * field as well. These functions accomplish that. */
+static PLHashNumber
+Get32BitNameHash(const SECItem *name)
+{
+ PLHashNumber rv = SECITEM_Hash(name);
+
+ PRUint8 *rvc = (PRUint8 *)&rv;
+ rvc[ name->len % sizeof(rv) ] ^= name->type;
+
+ return rv;
+}
+
+/* Put a name in the cache. Update the cert index in the sce.
+*/
+static PRUint32
+CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
+{
+ PRUint32 now;
+ PRUint32 ndx;
+ srvNameCacheEntry snce;
+
+ if (!name || name->len <= 0 ||
+ name->len > SSL_MAX_DNS_HOST_NAME) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return 0;
+ }
+
+ snce.type = name->type;
+ snce.nameLen = name->len;
+ PORT_Memcpy(snce.name, name->data, snce.nameLen);
+ SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data,
+ name->len);
+ /* get index of the next name */
+ ndx = Get32BitNameHash(name);
+ /* get lock on cert cache */
+ now = LockSidCacheLock(cache->srvNameCacheLock, 0);
+ if (now) {
+ if (cache->numSrvNameCacheEntries > 0) {
+ /* Fit the index into array */
+ ndx %= cache->numSrvNameCacheEntries;
+ /* write the entry */
+ cache->srvNameCacheData[ndx] = snce;
+ /* remember where we put it. */
+ sce->u.ssl3.srvNameIndex = ndx;
+ /* Copy hash into sid hash */
+ PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
+ }
+ UnlockSidCacheLock(cache->srvNameCacheLock);
+ }
+ return now;
+}
+
/*
** Convert local SID to shared memory one
*/
@@ -454,6 +530,7 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
to->sessionIDLength = from->u.ssl3.sessionIDLength;
to->u.ssl3.certIndex = -1;
+ to->u.ssl3.srvNameIndex = -1;
PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
to->sessionIDLength);
@@ -472,7 +549,9 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
** Caller must hold cache lock when calling this.
*/
static sslSessionID *
-ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce,
+ConvertToSID(sidCacheEntry * from,
+ certCacheEntry * pcce,
+ srvNameCacheEntry *psnce,
CERTCertDBHandle * dbHandle)
{
sslSessionID *to;
@@ -526,6 +605,17 @@ ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce,
to->u.ssl3.keys = from->u.ssl3.keys;
to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
+ if (from->u.ssl3.srvNameIndex != -1 && psnce) {
+ SECItem name;
+ SECStatus rv;
+ name.type = psnce->type;
+ name.len = psnce->nameLen;
+ name.data = psnce->name;
+ rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
@@ -582,7 +672,9 @@ ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce,
PORT_Free(to->u.ssl2.masterKey.data);
if (to->u.ssl2.cipherArg.data)
PORT_Free(to->u.ssl2.cipherArg.data);
- }
+ } else {
+ SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
+ }
PORT_Free(to);
}
return NULL;
@@ -682,12 +774,14 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
sslSessionID * sid = 0;
sidCacheEntry * psce;
certCacheEntry *pcce = 0;
+ srvNameCacheEntry *psnce = 0;
cacheDesc * cache = &globalCache;
PRUint32 now;
PRUint32 set;
PRInt32 cndx;
sidCacheEntry sce;
certCacheEntry cce;
+ srvNameCacheEntry snce;
set = SIDindex(cache, addr, sessionID, sessionIDLength);
now = LockSet(cache, set, 0);
@@ -696,36 +790,65 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
if (psce) {
- if (psce->version >= SSL_LIBRARY_VERSION_3_0 &&
- (cndx = psce->u.ssl3.certIndex) != -1) {
-
- PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
- if (gotLock) {
- pcce = &cache->certCacheData[cndx];
-
- /* See if the cert's session ID matches the sce cache. */
- if ((pcce->sessionIDLength == psce->sessionIDLength) &&
- !PORT_Memcmp(pcce->sessionID, psce->sessionID,
- pcce->sessionIDLength)) {
- cce = *pcce;
- } else {
- /* The cert doesen't match the SID cache entry,
- ** so invalidate the SID cache entry.
- */
- psce->valid = 0;
- psce = 0;
- pcce = 0;
- }
- UnlockSidCacheLock(cache->certCacheLock);
- } else {
- /* what the ??. Didn't get the cert cache lock.
- ** Don't invalidate the SID cache entry, but don't find it.
- */
- PORT_Assert(!("Didn't get cert Cache Lock!"));
- psce = 0;
- pcce = 0;
- }
- }
+ if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
+ if ((cndx = psce->u.ssl3.certIndex) != -1) {
+
+ PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
+ if (gotLock) {
+ pcce = &cache->certCacheData[cndx];
+
+ /* See if the cert's session ID matches the sce cache. */
+ if ((pcce->sessionIDLength == psce->sessionIDLength) &&
+ !PORT_Memcmp(pcce->sessionID, psce->sessionID,
+ pcce->sessionIDLength)) {
+ cce = *pcce;
+ } else {
+ /* The cert doesen't match the SID cache entry,
+ ** so invalidate the SID cache entry.
+ */
+ psce->valid = 0;
+ psce = 0;
+ pcce = 0;
+ }
+ UnlockSidCacheLock(cache->certCacheLock);
+ } else {
+ /* what the ??. Didn't get the cert cache lock.
+ ** Don't invalidate the SID cache entry, but don't find it.
+ */
+ PORT_Assert(!("Didn't get cert Cache Lock!"));
+ psce = 0;
+ pcce = 0;
+ }
+ }
+ if ((cndx = psce->u.ssl3.srvNameIndex) != -1) {
+ PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
+ now);
+ if (gotLock) {
+ psnce = &cache->srvNameCacheData[cndx];
+
+ if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash,
+ SHA256_LENGTH)) {
+ snce = *psnce;
+ } else {
+ /* The name doesen't match the SID cache entry,
+ ** so invalidate the SID cache entry.
+ */
+ psce->valid = 0;
+ psce = 0;
+ psnce = 0;
+ }
+ UnlockSidCacheLock(cache->srvNameCacheLock);
+ } else {
+ /* what the ??. Didn't get the cert cache lock.
+ ** Don't invalidate the SID cache entry, but don't find it.
+ */
+ PORT_Assert(!("Didn't get name Cache Lock!"));
+ psce = 0;
+ psnce = 0;
+ }
+
+ }
+ }
if (psce) {
psce->lastAccessTime = now;
sce = *psce; /* grab a copy while holding the lock */
@@ -736,7 +859,7 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
/* sce conains a copy of the cache entry.
** Convert shared memory format to local format
*/
- sid = ConvertToSID(&sce, pcce ? &cce : 0, dbHandle);
+ sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
}
return sid;
}
@@ -796,9 +919,14 @@ ServerSessionIDCache(sslSessionID *sid)
ConvertFromSID(&sce, sid);
- if ((version >= SSL_LIBRARY_VERSION_3_0) &&
- (sid->peerCert != NULL)) {
- now = CacheCert(cache, sid->peerCert, &sce);
+ if (version >= SSL_LIBRARY_VERSION_3_0) {
+ SECItem *name = &sid->u.ssl3.srvName;
+ if (name->len && name->data) {
+ now = CacheSrvName(cache, name, &sce);
+ }
+ if (sid->peerCert != NULL) {
+ now = CacheCert(cache, sid->peerCert, &sce);
+ }
}
set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
@@ -924,7 +1052,8 @@ CloseCache(cacheDesc *cache)
}
static SECStatus
-InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
+InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
+ int maxSrvNameCacheEntries, PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout, const char *directory, PRBool shared)
{
ptrdiff_t ptr;
@@ -973,6 +1102,11 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
cache->numSIDCacheSetsPerLock =
SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
+ cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
+ maxCertCacheEntries : 0;
+ cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries > 0) ?
+ maxSrvNameCacheEntries : 0;
+
/* compute size of shared memory, and offsets of all pointers */
ptr = 0;
cache->cacheMem = (char *)ptr;
@@ -981,7 +1115,8 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
cache->sidCacheLocks = (sidCacheLock *)ptr;
cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
cache->certCacheLock = cache->keyCacheLock + 1;
- ptr = (ptrdiff_t)(cache->certCacheLock + 1);
+ cache->srvNameCacheLock = cache->certCacheLock + 1;
+ ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->sidCacheSets = (sidCacheSet *)ptr;
@@ -996,10 +1131,12 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
cache->sidCacheSize =
(char *)cache->certCacheData - (char *)cache->sidCacheData;
- /* This is really a poor way to computer this! */
- cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
- if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
+ if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
+ /* This is really a poor way to computer this! */
+ cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
+ if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
+ }
ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
@@ -1030,6 +1167,15 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+ cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
+ if (cache->numSrvNameCacheEntries < 0) {
+ cache->numSrvNameCacheEntries = DEF_NAME_CACHE_ENTRIES;
+ }
+ cache->srvNameCacheSize =
+ cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
+ ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
cache->cacheMemSize = ptr;
if (ssl2_timeout) {
@@ -1113,6 +1259,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
*(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
*(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
*(ptrdiff_t *)(&cache->certCacheLock) += ptr;
+ *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
*(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
*(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
*(ptrdiff_t *)(&cache->certCacheData) += ptr;
@@ -1121,11 +1268,12 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
*(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
*(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
*(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
+ *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
/* initialize the locks */
init_time = ssl_Time();
pLock = cache->sidCacheLocks;
- for (locks_to_initialize = cache->numSIDCacheLocks + 2;
+ for (locks_to_initialize = cache->numSIDCacheLocks + 3;
locks_initialized < locks_to_initialize;
++locks_initialized, ++pLock ) {
@@ -1170,23 +1318,28 @@ SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
return SECSuccess;
}
-SECStatus
-SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
- int maxCacheEntries,
- PRUint32 ssl2_timeout,
- PRUint32 ssl3_timeout,
- const char * directory, PRBool shared)
+static SECStatus
+ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory,
+ PRBool shared,
+ int maxCacheEntries,
+ int maxCertCacheEntries,
+ int maxSrvNameCacheEntries)
{
SECStatus rv;
- PORT_Assert(sizeof(sidCacheEntry) == 192);
+ PORT_Assert(sizeof(sidCacheEntry) == 224);
PORT_Assert(sizeof(certCacheEntry) == 4096);
+ PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
myPid = SSL_GETPID();
if (!directory) {
directory = DEFAULT_CACHE_DIRECTORY;
}
- rv = InitCache(cache, maxCacheEntries, ssl2_timeout, ssl3_timeout,
+ rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
+ maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout,
directory, shared);
if (rv) {
SET_ERROR_CODE
@@ -1200,6 +1353,22 @@ SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
}
SECStatus
+SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
+ int maxCacheEntries,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory, PRBool shared)
+{
+ return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
+ ssl2_timeout,
+ ssl3_timeout,
+ directory,
+ shared,
+ maxCacheEntries,
+ -1, -1);
+}
+
+SECStatus
SSL_ConfigServerSessionIDCache( int maxCacheEntries,
PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
@@ -1231,11 +1400,13 @@ SSL_ShutdownServerSessionIDCache(void)
/* Use this function, instead of SSL_ConfigServerSessionIDCache,
* if the cache will be shared by multiple processes.
*/
-SECStatus
-SSL_ConfigMPServerSIDCache( int maxCacheEntries,
- PRUint32 ssl2_timeout,
- PRUint32 ssl3_timeout,
- const char * directory)
+static SECStatus
+ssl_ConfigMPServerSIDCacheWithOpt( PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory,
+ int maxCacheEntries,
+ int maxCertCacheEntries,
+ int maxSrvNameCacheEntries)
{
char * envValue;
char * inhValue;
@@ -1248,8 +1419,9 @@ SSL_ConfigMPServerSIDCache( int maxCacheEntries,
char fmString[PR_FILEMAP_STRING_BUFSIZE];
isMultiProcess = PR_TRUE;
- result = SSL_ConfigServerSessionIDCacheInstance(cache, maxCacheEntries,
- ssl2_timeout, ssl3_timeout, directory, PR_TRUE);
+ result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
+ ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
+ maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
if (result != SECSuccess)
return result;
@@ -1289,6 +1461,44 @@ SSL_ConfigMPServerSIDCache( int maxCacheEntries,
return result;
}
+/* Use this function, instead of SSL_ConfigServerSessionIDCache,
+ * if the cache will be shared by multiple processes.
+ */
+SECStatus
+SSL_ConfigMPServerSIDCache( int maxCacheEntries,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory)
+{
+ return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
+ ssl3_timeout,
+ directory,
+ maxCacheEntries,
+ -1, -1);
+}
+
+SECStatus
+SSL_ConfigServerSessionIDCacheWithOpt(
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory,
+ int maxCacheEntries,
+ int maxCertCacheEntries,
+ int maxSrvNameCacheEntries,
+ PRBool enableMPCache)
+{
+ if (!enableMPCache) {
+ ssl_InitSessionCacheLocks(PR_FALSE);
+ return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache,
+ ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
+ maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
+ } else {
+ return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
+ directory, maxCacheEntries, maxCertCacheEntries,
+ maxSrvNameCacheEntries);
+ }
+}
+
SECStatus
SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
{
@@ -1391,6 +1601,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
*(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
*(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
*(ptrdiff_t *)(&cache->certCacheLock) += ptr;
+ *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
*(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
*(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
*(ptrdiff_t *)(&cache->certCacheData) += ptr;
@@ -1399,6 +1610,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
*(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
*(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
*(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
+ *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
cache->cacheMemMap = my.cacheMemMap;
cache->cacheMem = my.cacheMem;
@@ -1420,7 +1632,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
/* note from jpierre : this should be free'd in child processes when
** a function is added to delete the SSL session cache in the future.
*/
- locks_to_initialize = cache->numSIDCacheLocks + 2;
+ locks_to_initialize = cache->numSIDCacheLocks + 3;
newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
if (!newLocks)
goto loser;
@@ -1443,6 +1655,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
/* also fix the key and cert cache which use the last 2 lock entries */
cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
cache->certCacheLock = cache->keyCacheLock + 1;
+ cache->srvNameCacheLock = cache->certCacheLock + 1;
#endif
PORT_Free(myEnvString);
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index 8788cf26d..c8edf21fd 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -304,7 +304,7 @@ ssl_DupSocket(sslSocket *os)
int i;
sslServerCerts * oc = os->serverCerts;
sslServerCerts * sc = ss->serverCerts;
-
+
for (i=kt_null; i < kt_kea_size; i++, oc++, sc++) {
if (oc->serverCert && oc->serverCertChain) {
sc->serverCert = CERT_DupCertificate(oc->serverCert);
@@ -333,6 +333,8 @@ ssl_DupSocket(sslSocket *os)
ss->authCertificateArg = os->authCertificateArg;
ss->getClientAuthData = os->getClientAuthData;
ss->getClientAuthDataArg = os->getClientAuthDataArg;
+ ss->sniSocketConfig = os->sniSocketConfig;
+ ss->sniSocketConfigArg = os->sniSocketConfigArg;
ss->handleBadCert = os->handleBadCert;
ss->badCertArg = os->badCertArg;
ss->handshakeCallback = os->handshakeCallback;
@@ -434,6 +436,11 @@ ssl_DestroySocketContents(sslSocket *ss)
ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
ss->ephemeralECDHKeyPair = NULL;
}
+ PORT_Assert(!ss->xtnData.sniNameArr);
+ if (ss->xtnData.sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ ss->xtnData.sniNameArr = NULL;
+ }
}
/*
@@ -1247,6 +1254,114 @@ SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd)
return fd;
}
+PRFileDesc *
+SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
+{
+ sslSocket * sm = NULL, *ss = NULL;
+ int i;
+ sslServerCerts * mc = sm->serverCerts;
+ sslServerCerts * sc = ss->serverCerts;
+ SECStatus rv;
+
+ if (model == NULL) {
+ PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+ return NULL;
+ }
+ sm = ssl_FindSocket(model);
+ if (sm == NULL) {
+ SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ReconfigFD",
+ SSL_GETPID(), model));
+ return NULL;
+ }
+ ss = ssl_FindSocket(fd);
+ PORT_Assert(ss);
+ if (ss == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ ss->opt = sm->opt;
+ PORT_Memcpy(ss->cipherSuites, sm->cipherSuites, sizeof sm->cipherSuites);
+
+ if (!ss->opt.useSecurity) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+ /* This int should be SSLKEAType, but CC on Irix complains,
+ * during the for loop.
+ */
+ for (i=kt_null; i < kt_kea_size; i++, mc++, sc++) {
+ if (mc->serverCert && mc->serverCertChain) {
+ if (sc->serverCert) {
+ CERT_DestroyCertificate(sc->serverCert);
+ }
+ sc->serverCert = CERT_DupCertificate(mc->serverCert);
+ if (sc->serverCertChain) {
+ CERT_DestroyCertificateList(sc->serverCertChain);
+ }
+ sc->serverCertChain = CERT_DupCertList(mc->serverCertChain);
+ if (!sc->serverCertChain)
+ goto loser;
+ }
+ if (mc->serverKeyPair) {
+ if (sc->serverKeyPair) {
+ ssl3_FreeKeyPair(sc->serverKeyPair);
+ }
+ sc->serverKeyPair = ssl3_GetKeyPairRef(mc->serverKeyPair);
+ sc->serverKeyBits = mc->serverKeyBits;
+ }
+ }
+ if (sm->stepDownKeyPair) {
+ if (ss->stepDownKeyPair) {
+ ssl3_FreeKeyPair(ss->stepDownKeyPair);
+ }
+ ss->stepDownKeyPair = ssl3_GetKeyPairRef(sm->stepDownKeyPair);
+ }
+ if (sm->ephemeralECDHKeyPair) {
+ if (ss->ephemeralECDHKeyPair) {
+ ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
+ }
+ ss->ephemeralECDHKeyPair =
+ ssl3_GetKeyPairRef(sm->ephemeralECDHKeyPair);
+ }
+ /* copy trust anchor names */
+ if (sm->ssl3.ca_list) {
+ if (ss->ssl3.ca_list) {
+ CERT_FreeDistNames(ss->ssl3.ca_list);
+ }
+ ss->ssl3.ca_list = CERT_DupDistNames(sm->ssl3.ca_list);
+ if (!ss->ssl3.ca_list) {
+ goto loser;
+ }
+ }
+
+ if (sm->authCertificate)
+ ss->authCertificate = sm->authCertificate;
+ if (sm->authCertificateArg)
+ ss->authCertificateArg = sm->authCertificateArg;
+ if (sm->getClientAuthData)
+ ss->getClientAuthData = sm->getClientAuthData;
+ if (sm->getClientAuthDataArg)
+ ss->getClientAuthDataArg = sm->getClientAuthDataArg;
+ if (sm->sniSocketConfig)
+ ss->sniSocketConfig = sm->sniSocketConfig;
+ if (sm->sniSocketConfigArg)
+ ss->sniSocketConfigArg = sm->sniSocketConfigArg;
+ if (sm->handleBadCert)
+ ss->handleBadCert = sm->handleBadCert;
+ if (sm->badCertArg)
+ ss->badCertArg = sm->badCertArg;
+ if (sm->handshakeCallback)
+ ss->handshakeCallback = sm->handshakeCallback;
+ if (sm->handshakeCallbackData)
+ ss->handshakeCallbackData = sm->handshakeCallbackData;
+ if (sm->pkcs11PinArg)
+ ss->pkcs11PinArg = sm->pkcs11PinArg;
+ return fd;
+loser:
+ return NULL;
+}
+
/************************************************************************/
/* The following functions are the TOP LEVEL SSL functions.
** They all get called through the NSPRIOMethods table below.
@@ -2235,6 +2350,8 @@ ssl_NewSocket(PRBool makeLocks)
/* Provide default implementation of hooks */
ss->authCertificate = SSL_AuthCertificate;
ss->authCertificateArg = (void *)ss->dbHandle;
+ ss->sniSocketConfig = NULL;
+ ss->sniSocketConfigArg = NULL;
ss->getClientAuthData = NULL;
ss->handleBadCert = NULL;
ss->badCertArg = NULL;
diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h
index 696b43486..1b7737bea 100644
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -189,4 +189,9 @@ typedef struct SSLCipherSuiteInfoStr {
} SSLCipherSuiteInfo;
+typedef enum {
+ SSL_sni_host_name = 0,
+ SSL_sni_type_total
+} SSLSniNameType;
+
#endif /* __sslt_h_ */
diff --git a/security/nss/tests/cert/cert.sh b/security/nss/tests/cert/cert.sh
index e5f96274e..939543826 100755
--- a/security/nss/tests/cert/cert.sh
+++ b/security/nss/tests/cert/cert.sh
@@ -906,6 +906,11 @@ cert_ssl()
echo "$SCRIPTNAME: Creating Server CA Issued Certificate for \\"
echo " ${HOSTADDR} ------------------------------------"
cert_create_cert ${SERVERDIR} "${HOSTADDR}" 100 ${D_SERVER}
+ echo "$SCRIPTNAME: Creating Server CA Issued Certificate for \\"
+ echo " ${HOSTADDR}-sni --------------------------------"
+ CERTSERIAL=101
+ CERTNAME="${HOST}-sni${sniCertCount}.${DOMSUF}"
+ cert_add_cert
CU_ACTION="Modify trust attributes of Root CA -t TC,TC,TC"
certu -M -n "TestCA" -t "TC,TC,TC" -d ${PROFILEDIR} -f "${R_PWFILE}"
if [ -n "$NSS_ENABLE_ECC" ] ; then
diff --git a/security/nss/tests/ssl/ssl.sh b/security/nss/tests/ssl/ssl.sh
index 6bf7783f0..ada3dad21 100755
--- a/security/nss/tests/ssl/ssl.sh
+++ b/security/nss/tests/ssl/ssl.sh
@@ -379,15 +379,22 @@ ssl_auth()
exec < ${SSLAUTH}
while read ectype value sparam cparam testname
do
+ [ -z "$ectype" ] && continue
echo "${testname}" | grep "don't require client auth" > /dev/null
CAUTH=$?
if [ "${CLIENT_MODE}" = "fips" -a "${CAUTH}" -eq 0 ] ; then
echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
+ elif [ "$ectype" = "SNI" -a "$NORM_EXT" = "Extended Test" ] ; then
+ echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
elif [ "$ectype" = "ECC" -a -z "$NSS_ENABLE_ECC" ] ; then
echo "$SCRIPTNAME: skipping $testname (ECC only)"
elif [ "`echo $ectype | cut -b 1`" != "#" ]; then
cparam=`echo $cparam | sed -e 's;_; ;g' -e "s/TestUser/$USER_NICKNAME/g" `
+ if [ "$ectype" = "SNI" ]; then
+ cparam=`echo $cparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
+ sparam=`echo $sparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
+ fi
start_selfserv
echo "tstclnt -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} -v ${CLIENT_OPTIONS} \\"
@@ -436,6 +443,8 @@ ssl_stress()
if [ "${SSL2}" -eq 0 -a "$NORM_EXT" = "Extended Test" ] ; then
echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
+ elif [ "$ectype" = "SNI" -a "$NORM_EXT" = "Extended Test" ] ; then
+ echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
elif [ "$ectype" = "ECC" -a -z "$NSS_ENABLE_ECC" ] ; then
echo "$SCRIPTNAME: skipping $testname (ECC only)"
elif [ "${SERVER_MODE}" = "fips" -o "${CLIENT_MODE}" = "fips" ] && [ "${SSL2}" -eq 0 ] ; then
@@ -444,6 +453,10 @@ ssl_stress()
echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
elif [ "`echo $ectype | cut -b 1`" != "#" ]; then
cparam=`echo $cparam | sed -e 's;_; ;g' -e "s/TestUser/$USER_NICKNAME/g" `
+ if [ "$ectype" = "SNI" ]; then
+ cparam=`echo $cparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
+ sparam=`echo $sparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
+ fi
# These tests need the mixed cert
# Stress TLS ECDH-RSA AES 128 CBC with SHA (no reuse)
@@ -497,8 +510,11 @@ ssl_crl_ssl()
exec < ${SSLAUTH}
while read ectype value sparam cparam testname
do
+ [ "$ectype" = "" ] && continue
if [ "$ectype" = "ECC" -a -z "$NSS_ENABLE_ECC" ] ; then
echo "$SCRIPTNAME: skipping $testname (ECC only)"
+ elif [ "$ectype" = "SNI" ]; then
+ continue
elif [ "`echo $ectype | cut -b 1`" != "#" ]; then
servarg=`echo $sparam | awk '{r=split($0,a,"-r") - 1;print r;}'`
pwd=`echo $cparam | grep nss`
@@ -682,8 +698,11 @@ ssl_crl_cache()
exec < ${SSLAUTH_TMP}
while read ectype value sparam cparam testname
do
+ [ "$ectype" = "" ] && continue
if [ "$ectype" = "ECC" -a -z "$NSS_ENABLE_ECC" ] ; then
echo "$SCRIPTNAME: skipping $testname (ECC only)"
+ elif [ "$ectype" = "SNI" ]; then
+ continue
else
servarg=`echo $sparam | awk '{r=split($0,a,"-r") - 1;print r;}'`
pwd=`echo $cparam | grep nss`
diff --git a/security/nss/tests/ssl/sslauth.txt b/security/nss/tests/ssl/sslauth.txt
index 07bfe5128..926dec263 100644
--- a/security/nss/tests/ssl/sslauth.txt
+++ b/security/nss/tests/ssl/sslauth.txt
@@ -83,3 +83,16 @@
# ECC 0 -r_-r_-r -T_-n_TestUser-ec_-w_nss SSL3 Request don't require client auth on 2nd hs (EC) (client auth)
# ECC 1 -r_-r_-r_-r -T_-n_TestUser-ec_-w_bogus SSL3 Require client auth on 2nd hs (EC) (bad password)
# ECC 0 -r_-r_-r_-r -T_-n_TestUser-ec_-w_nss SSL3 Require client auth on 2nd hs (EC) (client auth)
+#
+# SNI Tests
+#
+ SNI 0 -r_-a_Host-sni.Dom -2_-w_nss_-n_TestUser TLS Server hello response without SNI
+ SNI 0 -r_-a_Host-sni.Dom -2_-w_nss_-n_TestUser_-a_Host-sni.Dom TLS Server hello response with SNI
+ SNI 1 -r_-a_Host-sni.Dom -2_-w_nss_-n_TestUser_-a_Host-sni1.Dom TLS Server response with alert
+ SNI 0 -r_-a_Host-sni.Dom -2_-T_-w_nss_-n_TestUser SSL3 Server hello response without SNI
+ SNI 1 -r_-a_Host-sni.Dom -2_-T_-w_nss_-n_TestUser_-a_Host-sni.Dom SSL3 Server hello response with SNI: SSL don't have SH extensions
+# SNI 0 -r_-r_-r_-a_Host-sni.Dom -2_-w_nss_-n_TestUser TLS Server hello response without SNI
+# SNI 0 -r_-r_-r_-a_Host-sni.Dom -2_-w_nss_-n_TestUser_-a_Host-sni.Dom TLS Server hello response with SNI
+# SNI 1 -r_-r_-r_-a_Host-sni.Dom -2_-w_nss_-n_TestUser_-a_Host-sni.Dom_-a_Host.Dom TLS Server hello response with SNI: Change name on 2d HS
+# SNI 1 -r_-r_-r_-a_Host-sni.Dom -2_-w_nss_-n_TestUser_-a_Host-sni.Dom_-a_Host-sni1.Dom TLS Server hello response with SNI: Change name to invalid 2d HS
+# SNI 1 -r_-r_-r_-a_Host-sni.Dom -2_-w_nss_-n_TestUser_-a_Host-sni1.Dom TLS Server response with alert
diff --git a/security/nss/tests/ssl/sslstress.txt b/security/nss/tests/ssl/sslstress.txt
index 224d2bd94..16d5e6135 100644
--- a/security/nss/tests/ssl/sslstress.txt
+++ b/security/nss/tests/ssl/sslstress.txt
@@ -45,6 +45,7 @@
noECC 0 -u -2_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket)
noECC 0 -z -2_-c_1000_-C_c_-z Stress TLS RC4 128 with MD5 (compression)
noECC 0 -u_-z -2_-c_1000_-C_c_-u_-z Stress TLS RC4 128 with MD5 (session ticket, compression)
+ SNI 0 -u_-a_Host-sni.Dom -2_-3_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket, SNI)
#
# add client auth versions here...
@@ -55,6 +56,7 @@
noECC 0 -r_-r_-u -2_-c_100_-C_c_-n_TestUser_-u Stress TLS RC4 128 with MD5 (session ticket, client auth)
noECC 0 -r_-r_-z -2_-c_100_-C_c_-n_TestUser_-z Stress TLS RC4 128 with MD5 (compression, client auth)
noECC 0 -r_-r_-u_-z -2_-c_100_-C_c_-n_TestUser_-u_-z Stress TLS RC4 128 with MD5 (session ticket, compression, client auth)
+ SNI 0 -r_-r_-u_-a_Host-sni.Dom -2_-3_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket, SNI, client auth)
#
# ############################ ECC ciphers ############################