in plugins/inputs/opcua/opcua_util.go [148:279]
func (o *OpcUA) generateClientOpts(endpoints []*ua.EndpointDescription) ([]opcua.Option, error) {
opts := []opcua.Option{}
appuri := "urn:telegraf:gopcua:client"
appname := "Telegraf"
// ApplicationURI is automatically read from the cert so is not required if a cert if provided
opts = append(opts, opcua.ApplicationURI(appuri))
opts = append(opts, opcua.ApplicationName(appname))
opts = append(opts, opcua.RequestTimeout(time.Duration(o.RequestTimeout)))
certFile := o.Certificate
keyFile := o.PrivateKey
policy := o.SecurityPolicy
mode := o.SecurityMode
var err error
if certFile == "" && keyFile == "" {
if policy != "None" || mode != "None" {
certFile, keyFile, err = generateCert(appuri, 2048, certFile, keyFile, 365*24*time.Hour)
if err != nil {
return nil, err
}
}
}
var cert []byte
if certFile != "" && keyFile != "" {
debug.Printf("Loading cert/key from %s/%s", certFile, keyFile)
c, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
o.Log.Warnf("Failed to load certificate: %s", err)
} else {
pk, ok := c.PrivateKey.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("invalid private key")
}
cert = c.Certificate[0]
opts = append(opts, opcua.PrivateKey(pk), opcua.Certificate(cert))
}
}
var secPolicy string
switch {
case policy == "auto":
// set it later
case strings.HasPrefix(policy, ua.SecurityPolicyURIPrefix):
secPolicy = policy
policy = ""
case policy == "None" || policy == "Basic128Rsa15" || policy == "Basic256" || policy == "Basic256Sha256" || policy == "Aes128_Sha256_RsaOaep" || policy == "Aes256_Sha256_RsaPss":
secPolicy = ua.SecurityPolicyURIPrefix + policy
policy = ""
default:
return nil, fmt.Errorf("invalid security policy: %s", policy)
}
// Select the most appropriate authentication mode from server capabilities and user input
authMode, authOption, err := o.generateAuth(o.AuthMethod, cert, o.Username, o.Password)
if err != nil {
return nil, err
}
opts = append(opts, authOption)
var secMode ua.MessageSecurityMode
switch strings.ToLower(mode) {
case "auto":
case "none":
secMode = ua.MessageSecurityModeNone
mode = ""
case "sign":
secMode = ua.MessageSecurityModeSign
mode = ""
case "signandencrypt":
secMode = ua.MessageSecurityModeSignAndEncrypt
mode = ""
default:
return nil, fmt.Errorf("invalid security mode: %s", mode)
}
// Allow input of only one of sec-mode,sec-policy when choosing 'None'
if secMode == ua.MessageSecurityModeNone || secPolicy == ua.SecurityPolicyURINone {
secMode = ua.MessageSecurityModeNone
secPolicy = ua.SecurityPolicyURINone
}
// Find the best endpoint based on our input and server recommendation (highest SecurityMode+SecurityLevel)
var serverEndpoint *ua.EndpointDescription
switch {
case mode == "auto" && policy == "auto": // No user selection, choose best
for _, e := range endpoints {
if serverEndpoint == nil || (e.SecurityMode >= serverEndpoint.SecurityMode && e.SecurityLevel >= serverEndpoint.SecurityLevel) {
serverEndpoint = e
}
}
case mode != "auto" && policy == "auto": // User only cares about mode, select highest securitylevel with that mode
for _, e := range endpoints {
if e.SecurityMode == secMode && (serverEndpoint == nil || e.SecurityLevel >= serverEndpoint.SecurityLevel) {
serverEndpoint = e
}
}
case mode == "auto" && policy != "auto": // User only cares about policy, select highest securitylevel with that policy
for _, e := range endpoints {
if e.SecurityPolicyURI == secPolicy && (serverEndpoint == nil || e.SecurityLevel >= serverEndpoint.SecurityLevel) {
serverEndpoint = e
}
}
default: // User cares about both
for _, e := range endpoints {
if e.SecurityPolicyURI == secPolicy && e.SecurityMode == secMode && (serverEndpoint == nil || e.SecurityLevel >= serverEndpoint.SecurityLevel) {
serverEndpoint = e
}
}
}
if serverEndpoint == nil { // Didn't find an endpoint with matching policy and mode.
return nil, fmt.Errorf("unable to find suitable server endpoint with selected sec-policy and sec-mode")
}
secPolicy = serverEndpoint.SecurityPolicyURI
secMode = serverEndpoint.SecurityMode
// Check that the selected endpoint is a valid combo
err = validateEndpointConfig(endpoints, secPolicy, secMode, authMode)
if err != nil {
return nil, fmt.Errorf("error validating input: %s", err)
}
opts = append(opts, opcua.SecurityFromEndpoint(serverEndpoint, authMode))
return opts, nil
}