Repository: istio/istio
File: pilot/pkg/security/model/authentication.go (Go)

Code before:
	// at gateway agent.
	defaultValidationContext := &tls.CertificateValidationContext{
		MatchSubjectAltNames: util.StringToExactMatch(tlsOpts.SubjectAltNames),
	}
	tlsContext.ValidationContextType = &tls.CommonTlsContext_CombinedValidationContext{
		CombinedValidationContext: &tls.CommonTlsContext_CombinedCertificateValidationContext{
			DefaultValidationContext: defaultValidationContext,
			ValidationContextSdsSecretConfig: ConstructSdsSecretConfigForCredential(
				tlsOpts.CredentialName+SdsCaSuffix, credentialSocketExist, nil),
		},
	}
}

// ApplyCredentialSDSToServerCommonTLSContext applies the credentialName sds (Gateway/DestinationRule) to CommonTlsContext
// Used for building both gateway/sidecar TLS context
func ApplyCredentialSDSToServerCommonTLSContext(tlsContext *tls.CommonTlsContext,
	tlsOpts *networking.ServerTLSSettings, credentialSocketExist bool, push *model.PushContext,
) {
	// create SDS config for gateway/sidecar to fetch key/cert from agent.
	caCert := tlsOpts.CredentialName + SdsCaSuffix
	if len(tlsOpts.CredentialNames) > 0 {
		hasCacert := false
		// Handle multiple certificates for RSA and ECDSA
		tlsContext.TlsCertificateSdsSecretConfigs = []*tls.SdsSecretConfig{}
		for _, name := range tlsOpts.CredentialNames {
			if strings.HasSuffix(name, SdsCaSuffix) {
				if !hasCacert {
					caCert = name
					hasCacert = true
				}
			} else {
				tlsContext.TlsCertificateSdsSecretConfigs = append(tlsContext.TlsCertificateSdsSecretConfigs,
					ConstructSdsSecretConfigForCredential(name, credentialSocketExist, push))
			}
		}
		// If MUTUAL, we only support one CA certificate for all credentialNames. Thus we use the first one as CA.
		if !hasCacert {
			caCert = tlsOpts.CredentialNames[0] + SdsCaSuffix
		}
	} else {
		// Handle single certificate
		tlsContext.TlsCertificateSdsSecretConfigs = []*tls.SdsSecretConfig{
			ConstructSdsSecretConfigForCredential(tlsOpts.CredentialName, credentialSocketExist, push),
		}
	}

	// If tls mode is MUTUAL/OPTIONAL_MUTUAL, create SDS config for gateway/sidecar to fetch certificate validation context
	// at gateway agent. Otherwise, use the static certificate validation context config.
	if tlsOpts.Mode == networking.ServerTLSSettings_MUTUAL || tlsOpts.Mode == networking.ServerTLSSettings_OPTIONAL_MUTUAL {
		defaultValidationContext := &tls.CertificateValidationContext{
			MatchSubjectAltNames:  util.StringToExactMatch(tlsOpts.SubjectAltNames),

Review comment (security):
I am worried about this. First, let me say I think our existing API is quite problematic which is not your fault of course -- but something that is widely used and that we need to keep compatibility with its behavior.

Today, a user can put `credentialName: blah-cacert` and it will be treated as an opaque string. Now, the behavior is changed and we are implicitly deriving that they mean to use this as-is.

Code after:
	// at gateway agent.
	defaultValidationContext := &tls.CertificateValidationContext{
		MatchSubjectAltNames: util.StringToExactMatch(tlsOpts.SubjectAltNames),
	}
	tlsContext.ValidationContextType = &tls.CommonTlsContext_CombinedValidationContext{
		CombinedValidationContext: &tls.CommonTlsContext_CombinedCertificateValidationContext{
			DefaultValidationContext: defaultValidationContext,
			ValidationContextSdsSecretConfig: ConstructSdsSecretConfigForCredential(
				tlsOpts.CredentialName+SdsCaSuffix, credentialSocketExist, nil),
		},
	}
}

// ApplyCredentialSDSToServerCommonTLSContext applies the credentialName sds (Gateway/DestinationRule) to CommonTlsContext
// Used for building both gateway/sidecar TLS context
func ApplyCredentialSDSToServerCommonTLSContext(tlsContext *tls.CommonTlsContext,
	tlsOpts *networking.ServerTLSSettings, credentialSocketExist bool, push *model.PushContext,
) {
	// create SDS config for gateway/sidecar to fetch key/cert from agent.
	caCert := tlsOpts.CredentialName + SdsCaSuffix
	if len(tlsOpts.CredentialNames) > 0 {
		// Handle multiple certificates for RSA and ECDSA
		tlsContext.TlsCertificateSdsSecretConfigs = make([]*tls.SdsSecretConfig, len(tlsOpts.CredentialNames))
		for i, name := range tlsOpts.CredentialNames {
			tlsContext.TlsCertificateSdsSecretConfigs[i] = ConstructSdsSecretConfigForCredential(name, credentialSocketExist, push)
		}
		// If MUTUAL, we only support one CA certificate for all credentialNames. Thus we use the first one as CA.
		caCert = tlsOpts.CredentialNames[0] + SdsCaSuffix
	} else {
		// Handle single certificate
		tlsContext.TlsCertificateSdsSecretConfigs = []*tls.SdsSecretConfig{
			ConstructSdsSecretConfigForCredential(tlsOpts.CredentialName, credentialSocketExist, push),
		}
	}
	if tlsOpts.CaCertCredentialName != "" {
		caCert = tlsOpts.CaCertCredentialName
	}

	// If tls mode is MUTUAL/OPTIONAL_MUTUAL, create SDS config for gateway/sidecar to fetch certificate validation context
	// at gateway agent. Otherwise, use the static certificate validation context config.
	if tlsOpts.Mode == networking.ServerTLSSettings_MUTUAL || tlsOpts.Mode == networking.ServerTLSSettings_OPTIONAL_MUTUAL {
		defaultValidationContext := &tls.CertificateValidationContext{
			MatchSubjectAltNames:  util.StringToExactMatch(tlsOpts.SubjectAltNames),
			VerifyCertificateSpki: tlsOpts.VerifyCertificateSpki,
			VerifyCertificateHash: tlsOpts.VerifyCertificateHash,
		}
		tlsContext.ValidationContextType = &tls.CommonTlsContext_CombinedValidationContext{
			CombinedValidationContext: &tls.CommonTlsContext_CombinedCertificateValidationContext{
				DefaultValidationContext:         defaultValidationContext,
				ValidationContextSdsSecretConfig: ConstructSdsSecretConfigForCredential(caCert, credentialSocketExist, push),
			},