使用Golang crypto包生成私钥和x509证书后,MQTTS服务器无法正常连接
使用Golang crypto包生成私钥和x509证书后,MQTTS服务器无法正常连接 我需要生成一个私钥和证书来连接我的mqtts服务器。
我使用Golang的crypto包生成了一个私钥和证书,但无法正常连接到我的mqtts服务器。然而,我基于Golang代码生成的私钥通过OpenSSL创建的证书却可以正常连接到我的mqtts服务器。
Go版本: go version go1.20.1 darwin/arm64
我还没有尝试最新版本的Golang。
我使用以下代码来创建私钥和证书:
func GenerateCertificate(certificatePath string, keyPath string) error {
key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
serialNumber, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
if err != nil {
return err
}
now := time.Now()
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: "localhost",
Country: []string{"AU"},
Organization: []string{"Internet Widgits Pty Ltd"},
Province: []string{"Some-State"},
},
Issuer: pkix.Name{
CommonName: "localhost",
Country: []string{"AU"},
Organization: []string{"Internet Widgits Pty Ltd"},
Province: []string{"Some-State"},
},
NotBefore: now,
NotAfter: now.AddDate(10, 0, 0),
PublicKeyAlgorithm: x509.ECDSA,
SignatureAlgorithm: x509.ECDSAWithSHA256,
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
var certificateOut, keyOut io.Writer
if _, e := os.Stat(keyPath); os.IsNotExist(e) {
if _, err = os.Create(keyPath); err != nil {
return err
}
}
keyOut, err = os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
if _, e := os.Stat(certificatePath); os.IsNotExist(e) {
if _, err = os.Create(certificatePath); err != nil {
return err
}
}
certificateOut, err = os.OpenFile(certificatePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
secp256r1, err := asn1.Marshal(asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7})
if err != nil {
return err
}
paramBlock := pem.EncodeToMemory(&pem.Block{Type: "EC PARAMETERS", Bytes: secp256r1})
if _, err := keyOut.Write(paramBlock); err != nil {
return err
}
b, err := x509.MarshalECPrivateKey(key)
privBlock := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: b})
if _, err := keyOut.Write(privBlock);err != nil {
return err
}
certBlock := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
certificateOut.Write(certBlock)
return nil
}
接下来,我使用创建的私钥和证书来连接我的mqtts服务器:
func NewTLSConfig(certFile string, privateKey string) (*tls.Config, error) {
cert, err := tls.LoadX509KeyPair(certFile, privateKey)
if err != nil {
return nil, err
}
return &tls.Config{
ClientAuth: tls.NoClientCert,
ClientCAs: nil,
InsecureSkipVerify: true,
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{cert},
}, nil
}
if tlsConfig, err := util.NewTLSConfig("./config/certs/cert.pem", "./config/certs/key.pem"); err == nil {
opts.SetTLSConfig(tlsConfig)
} else {
return err
}
t.Client = mqtt.NewClient(opts)
if token := t.Client.Connect(); token.Wait() && token.Error() != nil {
logrus.Error("Connect to Thingsboard failed:", token.Error())
return token.Error()
}
然后我的mqtts服务器无法接收到任何证书

但是我使用openssl命令基于我用Golang代码创建的私钥生成了一个证书,然后用同样的方式连接到我的mqtts服务器,这是正常的。命令如下:
openssl req -new -key key.pem -x509 -nodes -days 365 -out cert.pem

请问我应该怎么做才能确保我的代码创建的cert.pem可以正常使用并连接到我的mqtts?非常感谢!!
更多关于使用Golang crypto包生成私钥和x509证书后,MQTTS服务器无法正常连接的实战教程也可以访问 https://www.itying.com/category-94-b0.html
关于MQTT以及它如何接受任何给定的证书,我无法提供太多帮助。
我几乎已经完成了自己的工具,用于管理我的私有密钥基础设施,从自定义的证书颁发机构到“标准”的SSL证书。对于这些证书,它会创建CSR(证书签名请求),签署证书,并以PEM编码格式存储在磁盘上。
代码已经可以工作,我的局域网已经在使用它。您可能想看看GitHub - jeanfrancoisgratton/certificateManager: 用于管理服务器证书和自定义根CA证书的Go工具,特别是src/cert/目录下的内容,当然还有README.md文件。
这可能对您有所帮助,特别是因为您可以摆脱使用外部工具(如openssl)来生成密钥等操作。
更多关于使用Golang crypto包生成私钥和x509证书后,MQTTS服务器无法正常连接的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题出在证书的编码格式上。你的代码生成的证书缺少必要的X.509扩展字段,而MQTTS服务器需要这些字段来验证证书的有效性。
以下是修复后的代码,添加了必要的扩展字段:
func GenerateCertificate(certificatePath string, keyPath string) error {
key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
serialNumber, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
if err != nil {
return err
}
now := time.Now()
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: "localhost",
Country: []string{"AU"},
Organization: []string{"Internet Widgits Pty Ltd"},
Province: []string{"Some-State"},
},
Issuer: pkix.Name{
CommonName: "localhost",
Country: []string{"AU"},
Organization: []string{"Internet Widgits Pty Ltd"},
Province: []string{"Some-State"},
},
NotBefore: now,
NotAfter: now.AddDate(10, 0, 0),
PublicKeyAlgorithm: x509.ECDSA,
SignatureAlgorithm: x509.ECDSAWithSHA256,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
IsCA: true,
DNSNames: []string{"localhost"},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
return err
}
// 创建证书文件
certOut, err := os.Create(certificatePath)
if err != nil {
return err
}
defer certOut.Close()
if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
return err
}
// 创建私钥文件
keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
defer keyOut.Close()
privBytes, err := x509.MarshalECPrivateKey(key)
if err != nil {
return err
}
if err := pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: privBytes}); err != nil {
return err
}
return nil
}
主要修改:
-
添加了必要的X.509扩展字段:
KeyUsage: 指定证书的用途ExtKeyUsage: 指定扩展的密钥用途(服务器认证和客户端认证)BasicConstraintsValid和IsCA: 设置基本约束DNSNames和IPAddresses: 添加主题备用名称
-
简化了文件写入逻辑,使用更直接的方式
-
移除了EC参数块,因为对于P256曲线,EC私钥已经包含了必要的参数信息
TLS配置代码保持不变:
func NewTLSConfig(certFile string, privateKey string) (*tls.Config, error) {
cert, err := tls.LoadX509KeyPair(certFile, privateKey)
if err != nil {
return nil, err
}
return &tls.Config{
ClientAuth: tls.NoClientCert,
ClientCAs: nil,
InsecureSkipVerify: true,
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{cert},
}, nil
}
这个修复后的代码会生成包含所有必要X.509扩展的证书,应该能够正常连接到MQTTS服务器。

