/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */#include"tls_agent.h"#include"databuffer.h"#include"keyhi.h"#include"pk11func.h"#include"ssl.h"#include"sslerr.h"#include"sslproto.h"#include"tls_parser.h"extern"C"{// This is not something that should make you happy.#include"libssl_internals.h"}#define GTEST_HAS_RTTI 0#include"gtest/gtest.h"#include"gtest_utils.h"#include"scoped_ptrs.h"externstd::stringg_working_dir_path;namespacenss_test{constchar*TlsAgent::states[]={"INIT","CONNECTING","CONNECTED","ERROR"};conststd::stringTlsAgent::kClient="client";// both sign and encryptconststd::stringTlsAgent::kRsa2048="rsa2048";// biggerconststd::stringTlsAgent::kServerRsa="rsa";// both sign and encryptconststd::stringTlsAgent::kServerRsaSign="rsa_sign";conststd::stringTlsAgent::kServerRsaPss="rsa_pss";conststd::stringTlsAgent::kServerRsaDecrypt="rsa_decrypt";conststd::stringTlsAgent::kServerRsaChain="rsa_chain";conststd::stringTlsAgent::kServerEcdsa256="ecdsa256";conststd::stringTlsAgent::kServerEcdsa384="ecdsa384";conststd::stringTlsAgent::kServerEcdsa521="ecdsa521";conststd::stringTlsAgent::kServerEcdhRsa="ecdh_rsa";conststd::stringTlsAgent::kServerEcdhEcdsa="ecdh_ecdsa";conststd::stringTlsAgent::kServerDsa="dsa";TlsAgent::TlsAgent(conststd::string&name,Rolerole,Modemode):name_(name),mode_(mode),role_(role),server_key_bits_(0),adapter_(newDummyPrSocket(role_str(),mode)),ssl_fd_(nullptr),state_(STATE_INIT),timer_handle_(nullptr),falsestart_enabled_(false),expected_version_(0),expected_cipher_suite_(0),expect_resumption_(false),expect_client_auth_(false),can_falsestart_hook_called_(false),sni_hook_called_(false),auth_certificate_hook_called_(false),expected_received_alert_(kTlsAlertCloseNotify),expected_received_alert_level_(kTlsAlertWarning),expected_sent_alert_(kTlsAlertCloseNotify),expected_sent_alert_level_(kTlsAlertWarning),handshake_callback_called_(false),error_code_(0),send_ctr_(0),recv_ctr_(0),expect_readwrite_error_(false),handshake_callback_(),auth_certificate_callback_(),sni_callback_(),expect_short_headers_(false){memset(&info_,0,sizeof(info_));memset(&csinfo_,0,sizeof(csinfo_));SECStatusrv=SSL_VersionRangeGetDefault(mode_==STREAM?ssl_variant_stream:ssl_variant_datagram,&vrange_);EXPECT_EQ(SECSuccess,rv);}TlsAgent::~TlsAgent(){if(timer_handle_){timer_handle_->Cancel();}if(adapter_){Poller::Instance()->Cancel(READABLE_EVENT,adapter_);}// Add failures manually, if any, so we don't throw in a destructor.if(expected_received_alert_!=kTlsAlertCloseNotify||expected_received_alert_level_!=kTlsAlertWarning){ADD_FAILURE()<<"Wrong expected_received_alert status";}if(expected_sent_alert_!=kTlsAlertCloseNotify||expected_sent_alert_level_!=kTlsAlertWarning){ADD_FAILURE()<<"Wrong expected_sent_alert status";}}voidTlsAgent::SetState(Statestate){if(state_==state)return;LOG("Changing state from "<<state_<<" to "<<state);state_=state;}/*static*/boolTlsAgent::LoadCertificate(conststd::string&name,ScopedCERTCertificate*cert,ScopedSECKEYPrivateKey*priv){cert->reset(PK11_FindCertFromNickname(name.c_str(),nullptr));EXPECT_NE(nullptr,cert->get());if(!cert->get())returnfalse;priv->reset(PK11_FindKeyByAnyCert(cert->get(),nullptr));EXPECT_NE(nullptr,priv->get());if(!priv->get())returnfalse;returntrue;}boolTlsAgent::ConfigServerCert(conststd::string&name,boolupdateKeyBits,constSSLExtraServerCertData*serverCertData){ScopedCERTCertificatecert;ScopedSECKEYPrivateKeypriv;if(!TlsAgent::LoadCertificate(name,&cert,&priv)){returnfalse;}if(updateKeyBits){ScopedSECKEYPublicKeypub(CERT_ExtractPublicKey(cert.get()));EXPECT_NE(nullptr,pub.get());if(!pub.get())returnfalse;server_key_bits_=SECKEY_PublicKeyStrengthInBits(pub.get());}SECStatusrv=SSL_ConfigSecureServer(ssl_fd(),nullptr,nullptr,ssl_kea_null);EXPECT_EQ(SECFailure,rv);rv=SSL_ConfigServerCert(ssl_fd(),cert.get(),priv.get(),serverCertData,serverCertData?sizeof(*serverCertData):0);returnrv==SECSuccess;}boolTlsAgent::EnsureTlsSetup(PRFileDesc*modelSocket){// Don't set up twiceif(ssl_fd_)returntrue;ScopedPRFileDescdummy_fd(adapter_->CreateFD());EXPECT_NE(nullptr,dummy_fd);if(!dummy_fd){returnfalse;}if(adapter_->mode()==STREAM){ssl_fd_.reset(SSL_ImportFD(modelSocket,dummy_fd.get()));}else{ssl_fd_.reset(DTLS_ImportFD(modelSocket,dummy_fd.get()));}EXPECT_NE(nullptr,ssl_fd_);if(!ssl_fd_){returnfalse;}dummy_fd.release();// Now subsumed by ssl_fd_.SECStatusrv=SSL_VersionRangeSet(ssl_fd(),&vrange_);EXPECT_EQ(SECSuccess,rv);if(rv!=SECSuccess)returnfalse;if(role_==SERVER){EXPECT_TRUE(ConfigServerCert(name_,true));rv=SSL_SNISocketConfigHook(ssl_fd(),SniHook,this);EXPECT_EQ(SECSuccess,rv);if(rv!=SECSuccess)returnfalse;ScopedCERTCertListanchors(CERT_NewCertList());rv=SSL_SetTrustAnchors(ssl_fd(),anchors.get());if(rv!=SECSuccess)returnfalse;}else{rv=SSL_SetURL(ssl_fd(),"server");EXPECT_EQ(SECSuccess,rv);if(rv!=SECSuccess)returnfalse;}rv=SSL_AuthCertificateHook(ssl_fd(),AuthCertificateHook,this);EXPECT_EQ(SECSuccess,rv);if(rv!=SECSuccess)returnfalse;rv=SSL_AlertReceivedCallback(ssl_fd(),AlertReceivedCallback,this);EXPECT_EQ(SECSuccess,rv);if(rv!=SECSuccess)returnfalse;rv=SSL_AlertSentCallback(ssl_fd(),AlertSentCallback,this);EXPECT_EQ(SECSuccess,rv);if(rv!=SECSuccess)returnfalse;rv=SSL_HandshakeCallback(ssl_fd(),HandshakeCallback,this);EXPECT_EQ(SECSuccess,rv);if(rv!=SECSuccess)returnfalse;returntrue;}voidTlsAgent::SetupClientAuth(){EXPECT_TRUE(EnsureTlsSetup());ASSERT_EQ(CLIENT,role_);EXPECT_EQ(SECSuccess,SSL_GetClientAuthDataHook(ssl_fd(),GetClientAuthDataHook,reinterpret_cast<void*>(this)));}SECStatusTlsAgent::GetClientAuthDataHook(void*self,PRFileDesc*fd,CERTDistNames*caNames,CERTCertificate**clientCert,SECKEYPrivateKey**clientKey){TlsAgent*agent=reinterpret_cast<TlsAgent*>(self);ScopedCERTCertificatepeerCert(SSL_PeerCertificate(agent->ssl_fd()));EXPECT_TRUE(peerCert)<<"Client should be able to see the server cert";ScopedCERTCertificatecert;ScopedSECKEYPrivateKeypriv;if(!TlsAgent::LoadCertificate(agent->name(),&cert,&priv)){returnSECFailure;}*clientCert=cert.release();*clientKey=priv.release();returnSECSuccess;}boolTlsAgent::GetPeerChainLength(size_t*count){CERTCertList*chain=SSL_PeerCertificateChain(ssl_fd());if(!chain)returnfalse;*count=0;for(PRCList*cursor=PR_NEXT_LINK(&chain->list);cursor!=&chain->list;cursor=PR_NEXT_LINK(cursor)){CERTCertListNode*node=(CERTCertListNode*)cursor;std::cerr<<node->cert->subjectName<<std::endl;++(*count);}CERT_DestroyCertList(chain);returntrue;}voidTlsAgent::CheckCipherSuite(uint16_tcipher_suite){EXPECT_EQ(csinfo_.cipherSuite,cipher_suite);}voidTlsAgent::RequestClientAuth(boolrequireAuth){EXPECT_TRUE(EnsureTlsSetup());ASSERT_EQ(SERVER,role_);EXPECT_EQ(SECSuccess,SSL_OptionSet(ssl_fd(),SSL_REQUEST_CERTIFICATE,PR_TRUE));EXPECT_EQ(SECSuccess,SSL_OptionSet(ssl_fd(),SSL_REQUIRE_CERTIFICATE,requireAuth?PR_TRUE:PR_FALSE));EXPECT_EQ(SECSuccess,SSL_AuthCertificateHook(ssl_fd(),&TlsAgent::ClientAuthenticated,this));expect_client_auth_=true;}voidTlsAgent::StartConnect(PRFileDesc*model){EXPECT_TRUE(EnsureTlsSetup(model));SECStatusrv;rv=SSL_ResetHandshake(ssl_fd(),role_==SERVER?PR_TRUE:PR_FALSE);EXPECT_EQ(SECSuccess,rv);SetState(STATE_CONNECTING);}voidTlsAgent::DisableAllCiphers(){for(size_ti=0;i<SSL_NumImplementedCiphers;++i){SECStatusrv=SSL_CipherPrefSet(ssl_fd(),SSL_ImplementedCiphers[i],PR_FALSE);EXPECT_EQ(SECSuccess,rv);}}// Not actually all groups, just the onece that we are actually willing// to use.conststd::vector<SSLNamedGroup>kAllDHEGroups={ssl_grp_ec_curve25519,ssl_grp_ec_secp256r1,ssl_grp_ec_secp384r1,ssl_grp_ec_secp521r1,ssl_grp_ffdhe_2048,ssl_grp_ffdhe_3072,ssl_grp_ffdhe_4096,ssl_grp_ffdhe_6144,ssl_grp_ffdhe_8192};conststd::vector<SSLNamedGroup>kECDHEGroups={ssl_grp_ec_curve25519,ssl_grp_ec_secp256r1,ssl_grp_ec_secp384r1,ssl_grp_ec_secp521r1};conststd::vector<SSLNamedGroup>kFFDHEGroups={ssl_grp_ffdhe_2048,ssl_grp_ffdhe_3072,ssl_grp_ffdhe_4096,ssl_grp_ffdhe_6144,ssl_grp_ffdhe_8192};// Defined because the big DHE groups are ridiculously slow.conststd::vector<SSLNamedGroup>kFasterDHEGroups={ssl_grp_ec_curve25519,ssl_grp_ec_secp256r1,ssl_grp_ec_secp384r1,ssl_grp_ffdhe_2048,ssl_grp_ffdhe_3072};voidTlsAgent::EnableCiphersByKeyExchange(SSLKEATypekea){EXPECT_TRUE(EnsureTlsSetup());for(size_ti=0;i<SSL_NumImplementedCiphers;++i){SSLCipherSuiteInfocsinfo;SECStatusrv=SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i],&csinfo,sizeof(csinfo));ASSERT_EQ(SECSuccess,rv);EXPECT_EQ(sizeof(csinfo),csinfo.length);if((csinfo.keaType==kea)||(csinfo.keaType==ssl_kea_tls13_any)){rv=SSL_CipherPrefSet(ssl_fd(),SSL_ImplementedCiphers[i],PR_TRUE);EXPECT_EQ(SECSuccess,rv);}}}voidTlsAgent::EnableGroupsByKeyExchange(SSLKEATypekea){switch(kea){casessl_kea_dh:ConfigNamedGroups(kFFDHEGroups);break;casessl_kea_ecdh:ConfigNamedGroups(kECDHEGroups);break;default:break;}}voidTlsAgent::EnableGroupsByAuthType(SSLAuthTypeauthType){if(authType==ssl_auth_ecdh_rsa||authType==ssl_auth_ecdh_ecdsa||authType==ssl_auth_ecdsa||authType==ssl_auth_tls13_any){ConfigNamedGroups(kECDHEGroups);}}voidTlsAgent::EnableCiphersByAuthType(SSLAuthTypeauthType){EXPECT_TRUE(EnsureTlsSetup());for(size_ti=0;i<SSL_NumImplementedCiphers;++i){SSLCipherSuiteInfocsinfo;SECStatusrv=SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i],&csinfo,sizeof(csinfo));ASSERT_EQ(SECSuccess,rv);if((csinfo.authType==authType)||(csinfo.keaType==ssl_kea_tls13_any)){rv=SSL_CipherPrefSet(ssl_fd(),SSL_ImplementedCiphers[i],PR_TRUE);EXPECT_EQ(SECSuccess,rv);}}}voidTlsAgent::EnableSingleCipher(uint16_tcipher){DisableAllCiphers();SECStatusrv=SSL_CipherPrefSet(ssl_fd(),cipher,PR_TRUE);EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::ConfigNamedGroups(conststd::vector<SSLNamedGroup>&groups){EXPECT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_NamedGroupConfig(ssl_fd(),&groups[0],groups.size());EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::SetSessionTicketsEnabled(boolen){EXPECT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_ENABLE_SESSION_TICKETS,en?PR_TRUE:PR_FALSE);EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::SetSessionCacheEnabled(boolen){EXPECT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_NO_CACHE,en?PR_FALSE:PR_TRUE);EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::Set0RttEnabled(boolen){EXPECT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_ENABLE_0RTT_DATA,en?PR_TRUE:PR_FALSE);EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::SetFallbackSCSVEnabled(boolen){EXPECT_TRUE(role_==CLIENT&&EnsureTlsSetup());SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_ENABLE_FALLBACK_SCSV,en?PR_TRUE:PR_FALSE);EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::SetShortHeadersEnabled(){EXPECT_TRUE(EnsureTlsSetup());SECStatusrv=SSLInt_EnableShortHeaders(ssl_fd());EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::SetVersionRange(uint16_tminver,uint16_tmaxver){vrange_.min=minver;vrange_.max=maxver;if(ssl_fd()){SECStatusrv=SSL_VersionRangeSet(ssl_fd(),&vrange_);EXPECT_EQ(SECSuccess,rv);}}voidTlsAgent::GetVersionRange(uint16_t*minver,uint16_t*maxver){*minver=vrange_.min;*maxver=vrange_.max;}voidTlsAgent::SetExpectedVersion(uint16_tversion){expected_version_=version;}voidTlsAgent::SetServerKeyBits(uint16_tbits){server_key_bits_=bits;}voidTlsAgent::ExpectReadWriteError(){expect_readwrite_error_=true;}voidTlsAgent::ExpectShortHeaders(){expect_short_headers_=true;}voidTlsAgent::SetSignatureSchemes(constSSLSignatureScheme*schemes,size_tcount){EXPECT_TRUE(EnsureTlsSetup());EXPECT_LE(count,SSL_SignatureMaxCount());EXPECT_EQ(SECSuccess,SSL_SignatureSchemePrefSet(ssl_fd(),schemes,static_cast<unsignedint>(count)));EXPECT_EQ(SECFailure,SSL_SignatureSchemePrefSet(ssl_fd(),schemes,0))<<"setting no schemes should fail and do nothing";std::vector<SSLSignatureScheme>configuredSchemes(count);unsignedintconfiguredCount;EXPECT_EQ(SECFailure,SSL_SignatureSchemePrefGet(ssl_fd(),nullptr,&configuredCount,1))<<"get schemes, schemes is nullptr";EXPECT_EQ(SECFailure,SSL_SignatureSchemePrefGet(ssl_fd(),&configuredSchemes[0],&configuredCount,0))<<"get schemes, too little space";EXPECT_EQ(SECFailure,SSL_SignatureSchemePrefGet(ssl_fd(),&configuredSchemes[0],nullptr,configuredSchemes.size()))<<"get schemes, countOut is nullptr";EXPECT_EQ(SECSuccess,SSL_SignatureSchemePrefGet(ssl_fd(),&configuredSchemes[0],&configuredCount,configuredSchemes.size()));// SignatureSchemePrefSet drops unsupported algorithms silently, so the// number that are configured might be fewer.EXPECT_LE(configuredCount,count);unsignedinti=0;for(unsignedintj=0;j<count&&i<configuredCount;++j){if(i<configuredCount&&schemes[j]==configuredSchemes[i]){++i;}}EXPECT_EQ(i,configuredCount)<<"schemes in use were all set";}voidTlsAgent::CheckKEA(SSLKEATypekea_type,SSLNamedGroupkea_group,size_tkea_size)const{EXPECT_EQ(STATE_CONNECTED,state_);EXPECT_EQ(kea_type,info_.keaType);if(kea_size==0){switch(kea_group){casessl_grp_ec_curve25519:kea_size=255;break;casessl_grp_ec_secp256r1:kea_size=256;break;casessl_grp_ec_secp384r1:kea_size=384;break;casessl_grp_ffdhe_2048:kea_size=2048;break;casessl_grp_ffdhe_3072:kea_size=3072;break;casessl_grp_ffdhe_custom:break;default:if(kea_type==ssl_kea_rsa){kea_size=server_key_bits_;}else{EXPECT_TRUE(false)<<"need to update group sizes";}}}if(kea_group!=ssl_grp_ffdhe_custom){EXPECT_EQ(kea_size,info_.keaKeyBits);EXPECT_EQ(kea_group,info_.keaGroup);}}voidTlsAgent::CheckAuthType(SSLAuthTypeauth_type,SSLSignatureSchemesig_scheme)const{EXPECT_EQ(STATE_CONNECTED,state_);EXPECT_EQ(auth_type,info_.authType);EXPECT_EQ(server_key_bits_,info_.authKeyBits);if(expected_version_<SSL_LIBRARY_VERSION_TLS_1_2){switch(auth_type){casessl_auth_rsa_sign:sig_scheme=ssl_sig_rsa_pkcs1_sha1md5;break;casessl_auth_ecdsa:sig_scheme=ssl_sig_ecdsa_sha1;break;default:break;}}EXPECT_EQ(sig_scheme,info_.signatureScheme);if(info_.protocolVersion>=SSL_LIBRARY_VERSION_TLS_1_3){return;}// Check authAlgorithm, which is the old value for authType. This is a second// switch// statement because default label is different.switch(auth_type){casessl_auth_rsa_sign:EXPECT_EQ(ssl_auth_rsa_decrypt,csinfo_.authAlgorithm)<<"authAlgorithm for RSA is always decrypt";break;casessl_auth_ecdh_rsa:EXPECT_EQ(ssl_auth_rsa_decrypt,csinfo_.authAlgorithm)<<"authAlgorithm for ECDH_RSA is RSA decrypt (i.e., wrong)";break;casessl_auth_ecdh_ecdsa:EXPECT_EQ(ssl_auth_ecdsa,csinfo_.authAlgorithm)<<"authAlgorithm for ECDH_ECDSA is ECDSA (i.e., wrong)";break;default:EXPECT_EQ(auth_type,csinfo_.authAlgorithm)<<"authAlgorithm is (usually) the same as authType";break;}}voidTlsAgent::EnableFalseStart(){EXPECT_TRUE(EnsureTlsSetup());falsestart_enabled_=true;EXPECT_EQ(SECSuccess,SSL_SetCanFalseStartCallback(ssl_fd(),CanFalseStartCallback,this));EXPECT_EQ(SECSuccess,SSL_OptionSet(ssl_fd(),SSL_ENABLE_FALSE_START,PR_TRUE));}voidTlsAgent::ExpectResumption(){expect_resumption_=true;}voidTlsAgent::EnableAlpn(constuint8_t*val,size_tlen){EXPECT_TRUE(EnsureTlsSetup());EXPECT_EQ(SECSuccess,SSL_OptionSet(ssl_fd(),SSL_ENABLE_ALPN,PR_TRUE));EXPECT_EQ(SECSuccess,SSL_SetNextProtoNego(ssl_fd(),val,len));}voidTlsAgent::CheckAlpn(SSLNextProtoStateexpected_state,conststd::string&expected)const{SSLNextProtoStatestate;charchosen[10];unsignedintchosen_len;SECStatusrv=SSL_GetNextProto(ssl_fd(),&state,reinterpret_cast<unsignedchar*>(chosen),&chosen_len,sizeof(chosen));EXPECT_EQ(SECSuccess,rv);EXPECT_EQ(expected_state,state);if(state==SSL_NEXT_PROTO_NO_SUPPORT){EXPECT_EQ("",expected);}else{EXPECT_NE("",expected);EXPECT_EQ(expected,std::string(chosen,chosen_len));}}voidTlsAgent::EnableSrtp(){EXPECT_TRUE(EnsureTlsSetup());constuint16_tciphers[]={SRTP_AES128_CM_HMAC_SHA1_80,SRTP_AES128_CM_HMAC_SHA1_32};EXPECT_EQ(SECSuccess,SSL_SetSRTPCiphers(ssl_fd(),ciphers,PR_ARRAY_SIZE(ciphers)));}voidTlsAgent::CheckSrtp()const{uint16_tactual;EXPECT_EQ(SECSuccess,SSL_GetSRTPCipher(ssl_fd(),&actual));EXPECT_EQ(SRTP_AES128_CM_HMAC_SHA1_80,actual);}voidTlsAgent::CheckErrorCode(int32_texpected)const{EXPECT_EQ(STATE_ERROR,state_);EXPECT_EQ(expected,error_code_)<<"Got error code "<<PORT_ErrorToName(error_code_)<<" expecting "<<PORT_ErrorToName(expected)<<std::endl;}staticuint8_tGetExpectedAlertLevel(uint8_talert){switch(alert){casekTlsAlertCloseNotify:casekTlsAlertEndOfEarlyData:returnkTlsAlertWarning;default:break;}returnkTlsAlertFatal;}voidTlsAgent::ExpectReceiveAlert(uint8_talert,uint8_tlevel){expected_received_alert_=alert;if(level==0){expected_received_alert_level_=GetExpectedAlertLevel(alert);}else{expected_received_alert_level_=level;}}voidTlsAgent::ExpectSendAlert(uint8_talert,uint8_tlevel){expected_sent_alert_=alert;if(level==0){expected_sent_alert_level_=GetExpectedAlertLevel(alert);}else{expected_sent_alert_level_=level;}}voidTlsAgent::CheckAlert(boolsent,constSSLAlert*alert){LOG(((alert->level==kTlsAlertWarning)?"Warning":"Fatal")<<" alert "<<(sent?"sent":"received")<<": "<<static_cast<int>(alert->description));auto&expected=sent?expected_sent_alert_:expected_received_alert_;auto&expected_level=sent?expected_sent_alert_level_:expected_received_alert_level_;/* Silently pass close_notify in case the test has already ended. */if(expected==kTlsAlertCloseNotify&&expected_level==kTlsAlertWarning&&alert->description==expected&&alert->level==expected_level){return;}EXPECT_EQ(expected,alert->description);EXPECT_EQ(expected_level,alert->level);expected=kTlsAlertCloseNotify;expected_level=kTlsAlertWarning;}voidTlsAgent::WaitForErrorCode(int32_texpected,uint32_tdelay)const{ASSERT_EQ(0,error_code_);WAIT_(error_code_!=0,delay);EXPECT_EQ(expected,error_code_)<<"Got error code "<<PORT_ErrorToName(error_code_)<<" expecting "<<PORT_ErrorToName(expected)<<std::endl;}voidTlsAgent::CheckPreliminaryInfo(){SSLPreliminaryChannelInfoinfo;EXPECT_EQ(SECSuccess,SSL_GetPreliminaryChannelInfo(ssl_fd(),&info,sizeof(info)));EXPECT_EQ(sizeof(info),info.length);EXPECT_TRUE(info.valuesSet&ssl_preinfo_version);EXPECT_TRUE(info.valuesSet&ssl_preinfo_cipher_suite);// A version of 0 is invalid and indicates no expectation. This value is// initialized to 0 so that tests that don't explicitly set an expected// version can negotiate a version.if(!expected_version_){expected_version_=info.protocolVersion;}EXPECT_EQ(expected_version_,info.protocolVersion);// As with the version; 0 is the null cipher suite (and also invalid).if(!expected_cipher_suite_){expected_cipher_suite_=info.cipherSuite;}EXPECT_EQ(expected_cipher_suite_,info.cipherSuite);}// Check that all the expected callbacks have been called.voidTlsAgent::CheckCallbacks()const{// If false start happens, the handshake is reported as being complete at the// point that false start happens.if(expect_resumption_||!falsestart_enabled_){EXPECT_TRUE(handshake_callback_called_);}// These callbacks shouldn't fire if we are resuming, except on TLS 1.3.if(role_==SERVER){PRBoolhave_sni=SSLInt_ExtensionNegotiated(ssl_fd(),ssl_server_name_xtn);EXPECT_EQ(((!expect_resumption_&&have_sni)||expected_version_>=SSL_LIBRARY_VERSION_TLS_1_3),sni_hook_called_);}else{EXPECT_EQ(!expect_resumption_,auth_certificate_hook_called_);// Note that this isn't unconditionally called, even with false start on.// But the callback is only skipped if a cipher that is ridiculously weak// (80 bits) is chosen. Don't test that: plan to remove bad ciphers.EXPECT_EQ(falsestart_enabled_&&!expect_resumption_,can_falsestart_hook_called_);}}voidTlsAgent::ResetPreliminaryInfo(){expected_version_=0;expected_cipher_suite_=0;}voidTlsAgent::Connected(){if(state_==STATE_CONNECTED){return;}LOG("Handshake success");CheckPreliminaryInfo();CheckCallbacks();SECStatusrv=SSL_GetChannelInfo(ssl_fd(),&info_,sizeof(info_));EXPECT_EQ(SECSuccess,rv);EXPECT_EQ(sizeof(info_),info_.length);// Preliminary values are exposed through callbacks during the handshake.// If either expected values were set or the callbacks were called, check// that the final values are correct.EXPECT_EQ(expected_version_,info_.protocolVersion);EXPECT_EQ(expected_cipher_suite_,info_.cipherSuite);rv=SSL_GetCipherSuiteInfo(info_.cipherSuite,&csinfo_,sizeof(csinfo_));EXPECT_EQ(SECSuccess,rv);EXPECT_EQ(sizeof(csinfo_),csinfo_.length);if(expected_version_>=SSL_LIBRARY_VERSION_TLS_1_3){PRInt32cipherSuites=SSLInt_CountTls13CipherSpecs(ssl_fd());// We use one ciphersuite in each direction, plus one that's kept around// by DTLS for retransmission.PRInt32expected=((mode_==DGRAM)&&(role_==CLIENT))?3:2;EXPECT_EQ(expected,cipherSuites);if(expected!=cipherSuites){SSLInt_PrintTls13CipherSpecs(ssl_fd());}}PRBoolshort_headers;rv=SSLInt_UsingShortHeaders(ssl_fd(),&short_headers);EXPECT_EQ(SECSuccess,rv);EXPECT_EQ((PRBool)expect_short_headers_,short_headers);SetState(STATE_CONNECTED);}voidTlsAgent::EnableExtendedMasterSecret(){ASSERT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_ENABLE_EXTENDED_MASTER_SECRET,PR_TRUE);ASSERT_EQ(SECSuccess,rv);}voidTlsAgent::CheckExtendedMasterSecret(boolexpected){if(version()>=SSL_LIBRARY_VERSION_TLS_1_3){expected=PR_TRUE;}ASSERT_EQ(expected,info_.extendedMasterSecretUsed!=PR_FALSE)<<"unexpected extended master secret state for "<<name_;}voidTlsAgent::CheckEarlyDataAccepted(boolexpected){if(version()<SSL_LIBRARY_VERSION_TLS_1_3){expected=false;}ASSERT_EQ(expected,info_.earlyDataAccepted!=PR_FALSE)<<"unexpected early data state for "<<name_;}voidTlsAgent::CheckSecretsDestroyed(){ASSERT_EQ(PR_TRUE,SSLInt_CheckSecretsDestroyed(ssl_fd()));}voidTlsAgent::DisableRollbackDetection(){ASSERT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_ROLLBACK_DETECTION,PR_FALSE);ASSERT_EQ(SECSuccess,rv);}voidTlsAgent::EnableCompression(){ASSERT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_ENABLE_DEFLATE,PR_TRUE);ASSERT_EQ(SECSuccess,rv);}voidTlsAgent::SetDowngradeCheckVersion(uint16_tversion){ASSERT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_SetDowngradeCheckVersion(ssl_fd(),version);ASSERT_EQ(SECSuccess,rv);}voidTlsAgent::Handshake(){LOGV("Handshake");SECStatusrv=SSL_ForceHandshake(ssl_fd());if(rv==SECSuccess){Connected();Poller::Instance()->Wait(READABLE_EVENT,adapter_,this,&TlsAgent::ReadableCallback);return;}int32_terr=PR_GetError();if(err==PR_WOULD_BLOCK_ERROR){LOGV("Would have blocked");if(mode_==DGRAM){if(timer_handle_){timer_handle_->Cancel();timer_handle_=nullptr;}PRIntervalTimetimeout;rv=DTLS_GetHandshakeTimeout(ssl_fd(),&timeout);if(rv==SECSuccess){Poller::Instance()->SetTimer(timeout+1,this,&TlsAgent::ReadableCallback,&timer_handle_);}}Poller::Instance()->Wait(READABLE_EVENT,adapter_,this,&TlsAgent::ReadableCallback);return;}LOG("Handshake failed with error "<<PORT_ErrorToName(err)<<": "<<PORT_ErrorToString(err));error_code_=err;SetState(STATE_ERROR);}voidTlsAgent::PrepareForRenegotiate(){EXPECT_EQ(STATE_CONNECTED,state_);SetState(STATE_CONNECTING);}voidTlsAgent::StartRenegotiate(){PrepareForRenegotiate();SECStatusrv=SSL_ReHandshake(ssl_fd(),PR_TRUE);EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::SendDirect(constDataBuffer&buf){LOG("Send Direct "<<buf);autopeer=adapter_->peer().lock();if(peer){peer->PacketReceived(buf);}else{LOG("Send Direct peer absent");}}staticboolErrorIsNonFatal(PRErrorCodecode){returncode==PR_WOULD_BLOCK_ERROR||code==SSL_ERROR_RX_SHORT_DTLS_READ;}voidTlsAgent::SendData(size_tbytes,size_tblocksize){uint8_tblock[4096];ASSERT_LT(blocksize,sizeof(block));while(bytes){size_ttosend=std::min(blocksize,bytes);for(size_ti=0;i<tosend;++i){block[i]=0xff&send_ctr_;++send_ctr_;}SendBuffer(DataBuffer(block,tosend));bytes-=tosend;}}voidTlsAgent::SendBuffer(constDataBuffer&buf){LOGV("Writing "<<buf.len()<<" bytes");int32_trv=PR_Write(ssl_fd(),buf.data(),buf.len());if(expect_readwrite_error_){EXPECT_GT(0,rv);EXPECT_NE(PR_WOULD_BLOCK_ERROR,error_code_);error_code_=PR_GetError();expect_readwrite_error_=false;}else{ASSERT_EQ(buf.len(),static_cast<size_t>(rv));}}voidTlsAgent::ReadBytes(){uint8_tblock[1024];int32_trv=PR_Read(ssl_fd(),block,sizeof(block));LOGV("ReadBytes "<<rv);int32_terr;if(rv>=0){size_tcount=static_cast<size_t>(rv);for(size_ti=0;i<count;++i){ASSERT_EQ(recv_ctr_&0xff,block[i]);recv_ctr_++;}}else{err=PR_GetError();LOG("Read error "<<PORT_ErrorToName(err)<<": "<<PORT_ErrorToString(err));if(err!=PR_WOULD_BLOCK_ERROR&&expect_readwrite_error_){error_code_=err;expect_readwrite_error_=false;}}// If closed, then don't bother waiting around.if(rv>0||(rv<0&&ErrorIsNonFatal(err))){LOGV("Re-arming");Poller::Instance()->Wait(READABLE_EVENT,adapter_,this,&TlsAgent::ReadableCallback);}}voidTlsAgent::ResetSentBytes(){send_ctr_=0;}voidTlsAgent::ConfigureSessionCache(SessionResumptionModemode){EXPECT_TRUE(EnsureTlsSetup());SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_NO_CACHE,mode&RESUME_SESSIONID?PR_FALSE:PR_TRUE);EXPECT_EQ(SECSuccess,rv);rv=SSL_OptionSet(ssl_fd(),SSL_ENABLE_SESSION_TICKETS,mode&RESUME_TICKET?PR_TRUE:PR_FALSE);EXPECT_EQ(SECSuccess,rv);}voidTlsAgent::DisableECDHEServerKeyReuse(){ASSERT_TRUE(EnsureTlsSetup());ASSERT_EQ(TlsAgent::SERVER,role_);SECStatusrv=SSL_OptionSet(ssl_fd(),SSL_REUSE_SERVER_ECDHE_KEY,PR_FALSE);EXPECT_EQ(SECSuccess,rv);}staticconststd::stringkTlsRolesAllArr[]={"CLIENT","SERVER"};::testing::internal::ParamGenerator<std::string>TlsAgentTestBase::kTlsRolesAll=::testing::ValuesIn(kTlsRolesAllArr);voidTlsAgentTestBase::SetUp(){SSL_ConfigServerSessionIDCache(1024,0,0,g_working_dir_path.c_str());}voidTlsAgentTestBase::TearDown(){agent_=nullptr;SSL_ClearSessionCache();SSL_ShutdownServerSessionIDCache();}voidTlsAgentTestBase::Reset(conststd::string&server_name){agent_.reset(newTlsAgent(role_==TlsAgent::CLIENT?TlsAgent::kClient:server_name,role_,mode_));if(version_){agent_->SetVersionRange(version_,version_);}agent_->adapter()->SetPeer(sink_adapter_);agent_->StartConnect();}voidTlsAgentTestBase::EnsureInit(){if(!agent_){Reset();}conststd::vector<SSLNamedGroup>groups={ssl_grp_ec_curve25519,ssl_grp_ec_secp256r1,ssl_grp_ec_secp384r1,ssl_grp_ffdhe_2048};agent_->ConfigNamedGroups(groups);}voidTlsAgentTestBase::ExpectAlert(uint8_talert){EnsureInit();agent_->ExpectSendAlert(alert);}voidTlsAgentTestBase::ProcessMessage(constDataBuffer&buffer,TlsAgent::Stateexpected_state,int32_terror_code){std::cerr<<"Process message: "<<buffer<<std::endl;EnsureInit();agent_->adapter()->PacketReceived(buffer);agent_->Handshake();ASSERT_EQ(expected_state,agent_->state());if(expected_state==TlsAgent::STATE_ERROR){ASSERT_EQ(error_code,agent_->error_code());}}voidTlsAgentTestBase::MakeRecord(Modemode,uint8_ttype,uint16_tversion,constuint8_t*buf,size_tlen,DataBuffer*out,uint64_tseq_num){size_tindex=0;index=out->Write(index,type,1);index=out->Write(index,mode==STREAM?version:TlsVersionToDtlsVersion(version),2);if(mode==DGRAM){index=out->Write(index,seq_num>>32,4);index=out->Write(index,seq_num&PR_UINT32_MAX,4);}index=out->Write(index,len,2);out->Write(index,buf,len);}voidTlsAgentTestBase::MakeRecord(uint8_ttype,uint16_tversion,constuint8_t*buf,size_tlen,DataBuffer*out,uint64_tseq_num)const{MakeRecord(mode_,type,version,buf,len,out,seq_num);}voidTlsAgentTestBase::MakeHandshakeMessage(uint8_ths_type,constuint8_t*data,size_ths_len,DataBuffer*out,uint64_tseq_num)const{returnMakeHandshakeMessageFragment(hs_type,data,hs_len,out,seq_num,0,0);}voidTlsAgentTestBase::MakeHandshakeMessageFragment(uint8_ths_type,constuint8_t*data,size_ths_len,DataBuffer*out,uint64_tseq_num,uint32_tfragment_offset,uint32_tfragment_length)const{size_tindex=0;if(!fragment_length)fragment_length=hs_len;index=out->Write(index,hs_type,1);// Handshake record type.index=out->Write(index,hs_len,3);// Handshake lengthif(mode_==DGRAM){index=out->Write(index,seq_num,2);index=out->Write(index,fragment_offset,3);index=out->Write(index,fragment_length,3);}if(data){index=out->Write(index,data,fragment_length);}else{for(size_ti=0;i<fragment_length;++i){index=out->Write(index,1,1);}}}voidTlsAgentTestBase::MakeTrivialHandshakeRecord(uint8_ths_type,size_ths_len,DataBuffer*out){size_tindex=0;index=out->Write(index,kTlsHandshakeType,1);// Content Typeindex=out->Write(index,3,1);// Version highindex=out->Write(index,1,1);// Version lowindex=out->Write(index,4+hs_len,2);// Lengthindex=out->Write(index,hs_type,1);// Handshake record type.index=out->Write(index,hs_len,3);// Handshake lengthfor(size_ti=0;i<hs_len;++i){index=out->Write(index,1,1);}}}// namespace nss_test