要使用无/无以上的任何安全策略或使用用户名/密码登录,您需要拥有现有的 X.509 证书或自己生成一个。
请注意,证书分为两部分,一个公共证书和一个私钥。你需要两者。公共证书将被发送到 Kepware 服务器,而私钥将留在客户端并用于加密和解密。
endpoints, err := opcua.GetEndpoints(context.Background(), cfg.Endpoint)
if err != nil {
return nil, fmt.Errorf("OPC GetEndpoints: %w", err)
}
policy := ua.SecurityPolicyURINone // Replace this with a constant of your security policy
mode := ua.MessageSecurityModeNone // Replace this with a constant of your security mode
ep := opcua.SelectEndpoint(endpoints, policy, mode)
c, err := generateCert() // This is where you generate the certificate
if err != nil {
return nil, fmt.Errorf("generateCert: %w", err)
}
pk, ok := c.PrivateKey.(*rsa.PrivateKey) // This is where you set the private key
if !ok {
return nil, fmt.Errorf("invalid private key")
}
cert := c.Certificate[0]
opts := []opcua.Option{
opcua.SecurityPolicy(policy),
opcua.SecurityMode(mode),
opcua.PrivateKey(pk),
opcua.Certificate(cert), // Set the certificate for the OPC UA Client
opcua.AuthUsername(cfg.Username, cfg.Password), // Use this if you are using username and password
opcua.SecurityFromEndpoint(ep, ua.UserTokenTypeUserName),
opcua.SessionTimeout(30 * time.Minute),
opcua.AutoReconnect(true),
opcua.ReconnectInterval(time.Second * 10),
opcua.Lifetime(30 * time.Minute),
opcua.RequestTimeout(3 * time.Second),
}
使用以下内容生成 X.509 证书。
func generateCert() (*tls.Certificate, error) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, fmt.Errorf("failed to generate private key: %s", err)
}
notBefore := time.Now()
notAfter := notBefore.Add(365 * 24 * time.Hour) // 1 year
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, fmt.Errorf("failed to generate serial number: %s", err)
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Test Client"},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageContentCommitment | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
}
host := "urn:testing:client"
if ip := net.ParseIP(host); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, host)
}
if uri, err := url.Parse(host); err == nil {
template.URIs = append(template.URIs, uri)
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
if err != nil {
return nil, fmt.Errorf("failed to create certificate: %s", err)
}
certBuf := bytes.NewBuffer(nil)
if err := pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
return nil, fmt.Errorf("failed to encode certificate: %s", err)
}
keyBuf := bytes.NewBuffer(nil)
if err := pem.Encode(keyBuf, pemBlockForKey(priv)); err != nil {
return nil, fmt.Errorf("failed to encode key: %s", err)
}
cert, err := tls.X509KeyPair(certBuf.Bytes(), keyBuf.Bytes())
return &cert, err
}
这是一个直接来自 gopcua 项目的示例:
https://github.com/gopcua/opcua/blob/main/examples/crypto/generate_cert.go