登录
首页 >  Golang >  Go问答

实现带有证书的 Golang Opc UA 客户端

来源:stackoverflow

时间:2024-02-26 20:54:24 174浏览 收藏

珍惜时间,勤奋学习!今天给大家带来《实现带有证书的 Golang Opc UA 客户端》,正文内容主要涉及到等等,如果你正在学习Golang,或者是对Golang有疑问,欢迎大家关注我!后面我会持续更新相关内容的,希望都能帮到正在学习的大家!

问题内容

我正在尝试使用证书连接本地 kepware opc ua 服务器。 opc ua 服务器安全信息:

在golang应用程序中,我使用“github.com/gopcua/opcua/ua”opc客户端包。我创建密钥对,并为它们提供变量路径并在配置中使用它们:

opts := []opcua.Option{
            opcua.SecurityPolicy(relatedConnection.SecurityPolicy),
            opcua.SecurityModeString(relatedConnection.SecurityMode),
            opcua.CertificateFile(certFile),
            opcua.PrivateKeyFile(keyFile),
            opcua.AutoReconnect(true),
            opcua.ReconnectInterval(time.Second * 5),
            opcua.RequestTimeout(time.Second * 3),
        }

当安全策略和模式为none时,我可以毫无问题地连接到服务器。当我选择这些安全策略时,我不知道如何实现代码或 ssl 密钥对来连接服务器。


正确答案


为了使用无/无以上的任何安全策略或使用用户名/密码登录,您需要拥有现有的 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

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>