|  | // Copyright 2025 The BoringSSL Authors | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //	https://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | package runner | 
|  |  | 
|  | func addExtendedMasterSecretTests() { | 
|  | const expectEMSFlag = "-expect-extended-master-secret" | 
|  |  | 
|  | for _, with := range []bool{false, true} { | 
|  | prefix := "No" | 
|  | if with { | 
|  | prefix = "" | 
|  | } | 
|  |  | 
|  | for _, isClient := range []bool{false, true} { | 
|  | suffix := "-Server" | 
|  | testType := serverTest | 
|  | if isClient { | 
|  | suffix = "-Client" | 
|  | testType = clientTest | 
|  | } | 
|  |  | 
|  | for _, ver := range tlsVersions { | 
|  | // In TLS 1.3, the extension is irrelevant and | 
|  | // always reports as enabled. | 
|  | var flags []string | 
|  | if with || ver.version >= VersionTLS13 { | 
|  | flags = []string{expectEMSFlag} | 
|  | } | 
|  |  | 
|  | testCases = append(testCases, testCase{ | 
|  | testType: testType, | 
|  | name:     prefix + "ExtendedMasterSecret-" + ver.name + suffix, | 
|  | config: Config{ | 
|  | MinVersion: ver.version, | 
|  | MaxVersion: ver.version, | 
|  | Bugs: ProtocolBugs{ | 
|  | NoExtendedMasterSecret:      !with, | 
|  | RequireExtendedMasterSecret: with, | 
|  | }, | 
|  | }, | 
|  | flags: flags, | 
|  | }) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for _, isClient := range []bool{false, true} { | 
|  | for _, supportedInFirstConnection := range []bool{false, true} { | 
|  | for _, supportedInResumeConnection := range []bool{false, true} { | 
|  | boolToWord := func(b bool) string { | 
|  | if b { | 
|  | return "Yes" | 
|  | } | 
|  | return "No" | 
|  | } | 
|  | suffix := boolToWord(supportedInFirstConnection) + "To" + boolToWord(supportedInResumeConnection) + "-" | 
|  | if isClient { | 
|  | suffix += "Client" | 
|  | } else { | 
|  | suffix += "Server" | 
|  | } | 
|  |  | 
|  | supportedConfig := Config{ | 
|  | MaxVersion: VersionTLS12, | 
|  | Bugs: ProtocolBugs{ | 
|  | RequireExtendedMasterSecret: true, | 
|  | }, | 
|  | } | 
|  |  | 
|  | noSupportConfig := Config{ | 
|  | MaxVersion: VersionTLS12, | 
|  | Bugs: ProtocolBugs{ | 
|  | NoExtendedMasterSecret: true, | 
|  | }, | 
|  | } | 
|  |  | 
|  | test := testCase{ | 
|  | name:          "ExtendedMasterSecret-" + suffix, | 
|  | resumeSession: true, | 
|  | } | 
|  |  | 
|  | if !isClient { | 
|  | test.testType = serverTest | 
|  | } | 
|  |  | 
|  | if supportedInFirstConnection { | 
|  | test.config = supportedConfig | 
|  | } else { | 
|  | test.config = noSupportConfig | 
|  | } | 
|  |  | 
|  | if supportedInResumeConnection { | 
|  | test.resumeConfig = &supportedConfig | 
|  | } else { | 
|  | test.resumeConfig = &noSupportConfig | 
|  | } | 
|  |  | 
|  | switch suffix { | 
|  | case "YesToYes-Client", "YesToYes-Server": | 
|  | // When a session is resumed, it should | 
|  | // still be aware that its master | 
|  | // secret was generated via EMS and | 
|  | // thus it's safe to use tls-unique. | 
|  | test.flags = []string{expectEMSFlag} | 
|  | case "NoToYes-Server": | 
|  | // If an original connection did not | 
|  | // contain EMS, but a resumption | 
|  | // handshake does, then a server should | 
|  | // not resume the session. | 
|  | test.expectResumeRejected = true | 
|  | case "YesToNo-Server": | 
|  | // Resuming an EMS session without the | 
|  | // EMS extension should cause the | 
|  | // server to abort the connection. | 
|  | test.shouldFail = true | 
|  | test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" | 
|  | case "NoToYes-Client": | 
|  | // A client should abort a connection | 
|  | // where the server resumed a non-EMS | 
|  | // session but echoed the EMS | 
|  | // extension. | 
|  | test.shouldFail = true | 
|  | test.expectedError = ":RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION:" | 
|  | case "YesToNo-Client": | 
|  | // A client should abort a connection | 
|  | // where the server didn't echo EMS | 
|  | // when the session used it. | 
|  | test.shouldFail = true | 
|  | test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" | 
|  | } | 
|  |  | 
|  | testCases = append(testCases, test) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Switching EMS on renegotiation is forbidden. | 
|  | testCases = append(testCases, testCase{ | 
|  | name: "ExtendedMasterSecret-Renego-NoEMS", | 
|  | config: Config{ | 
|  | MaxVersion: VersionTLS12, | 
|  | Bugs: ProtocolBugs{ | 
|  | NoExtendedMasterSecret:                true, | 
|  | NoExtendedMasterSecretOnRenegotiation: true, | 
|  | }, | 
|  | }, | 
|  | renegotiate: 1, | 
|  | flags: []string{ | 
|  | "-renegotiate-freely", | 
|  | "-expect-total-renegotiations", "1", | 
|  | }, | 
|  | }) | 
|  |  | 
|  | testCases = append(testCases, testCase{ | 
|  | name: "ExtendedMasterSecret-Renego-Upgrade", | 
|  | config: Config{ | 
|  | MaxVersion: VersionTLS12, | 
|  | Bugs: ProtocolBugs{ | 
|  | NoExtendedMasterSecret: true, | 
|  | }, | 
|  | }, | 
|  | renegotiate: 1, | 
|  | flags: []string{ | 
|  | "-renegotiate-freely", | 
|  | "-expect-total-renegotiations", "1", | 
|  | }, | 
|  | shouldFail:    true, | 
|  | expectedError: ":RENEGOTIATION_EMS_MISMATCH:", | 
|  | }) | 
|  |  | 
|  | testCases = append(testCases, testCase{ | 
|  | name: "ExtendedMasterSecret-Renego-Downgrade", | 
|  | config: Config{ | 
|  | MaxVersion: VersionTLS12, | 
|  | Bugs: ProtocolBugs{ | 
|  | NoExtendedMasterSecretOnRenegotiation: true, | 
|  | }, | 
|  | }, | 
|  | renegotiate: 1, | 
|  | flags: []string{ | 
|  | "-renegotiate-freely", | 
|  | "-expect-total-renegotiations", "1", | 
|  | }, | 
|  | shouldFail:    true, | 
|  | expectedError: ":RENEGOTIATION_EMS_MISMATCH:", | 
|  | }) | 
|  | } |