diff options
Diffstat (limited to 'security/nss')
-rw-r--r-- | security/nss/cmd/selfserv/selfserv.c | 103 | ||||
-rw-r--r-- | security/nss/cmd/tstclnt/tstclnt.c | 42 | ||||
-rw-r--r-- | security/nss/lib/certdb/cert.h | 8 | ||||
-rw-r--r-- | security/nss/lib/certhigh/certhigh.c | 95 | ||||
-rw-r--r-- | security/nss/lib/nss/nss.def | 7 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl.def | 10 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl.h | 83 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 227 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3ext.c | 184 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslimpl.h | 30 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslinfo.c | 38 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslreveal.c | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsecur.c | 203 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsnce.c | 333 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsock.c | 119 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslt.h | 5 | ||||
-rwxr-xr-x | security/nss/tests/cert/cert.sh | 5 | ||||
-rwxr-xr-x | security/nss/tests/ssl/ssl.sh | 19 | ||||
-rw-r--r-- | security/nss/tests/ssl/sslauth.txt | 13 | ||||
-rw-r--r-- | security/nss/tests/ssl/sslstress.txt | 2 |
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 ############################ |