自签名证书的TLS

31

我正在尝试使用自签名服务器证书建立TLS连接。

我使用这个示例代码生成了证书:http://golang.org/src/pkg/crypto/tls/generate_cert.go

我的相关客户端代码如下:

// server cert is self signed -> server_cert == ca_cert
CA_Pool := x509.NewCertPool()
severCert, err := ioutil.ReadFile("./cert.pem")
if err != nil {
    log.Fatal("Could not load server certificate!")
}
CA_Pool.AppendCertsFromPEM(severCert)

config := tls.Config{RootCAs: CA_Pool}

conn, err := tls.Dial("tcp", "127.0.0.1:8000", &config)
if err != nil {
    log.Fatalf("client: dial: %s", err)
}

相关的服务器代码如下:

cert, err := tls.LoadX509KeyPair("./cert.pem", "./key.pem")
config := tls.Config{Certificates: []tls.Certificate{cert}}
listener, err := tls.Listen("tcp", "127.0.0.1:8000", &config)

for {
    conn, err := listener.Accept()
    if err != nil {
        log.Printf("server: accept: %s", err)
        break
    }
    log.Printf("server: accepted from %s", conn.RemoteAddr())
    go handleConnection(conn)
}

由于服务器证书是自签名的,因此将同一证书用于服务器和客户端 CA_Pool,但似乎不起作用,因为我始终会收到这个错误:

client: dial: x509: certificate signed by unknown authority 
(possibly because of "x509: invalid signature: parent certificate
cannot sign this kind of certificate" while trying to verify 
candidate authority certificate "serial:0")

我的错误在哪里?

6个回答

36

最终用go内置的x509.CreateCertificate成功了,问题在于我没有设置IsCA:true标志我只设置了x509.KeyUsageCertSign,这使创建自签名证书可以工作,但在验证证书链时崩溃。


谢谢Zap,这帮助我指明了解决问题的方向。我发布了一个短小的自包含示例,其中包括了Ansible自动化解决方案及其说明,作为另一个相关问题的答案。我不想重复我的答案,所以我会链接到其他相关的问答中。https://dev59.com/P5Lea4cB1Zd3GeqPxhOp#59154493 - neokyle
似乎还需要 BasicConstraintsValid: true - Aaron Loo

9
问题在于服务器端配置需要一个CA证书,并且该CA必须签署了服务器的证书。
我编写了一些Go代码,可以生成CA证书,但是没有经过任何人的审核,而且主要是用来玩弄客户端证书的玩具。最安全的方法可能是使用openssl ca来生成和签署证书。基本步骤如下:
  1. 生成CA证书
  2. 生成服务器密钥
  3. 使用CA证书对服务器密钥进行签名
  4. 将CA证书添加到客户端的tls.Config RootCAs
  5. 使用服务器密钥和签名证书设置服务器的tls.Config

4

好的,我之前使用了EasyCert,但现在出现了一个错误:“client: dial: x509: 无法验证127.0.0.1的证书,因为它不包含任何IP SANs”,那么IS SANs是什么? - Zap
我要冒昧地说,您可能会在Go中遇到一个错误:https://code.google.com/p/go/issues/detail?id=4658 如果可能的话,尝试升级您的Go版本。 - Ralph Caraveo

0
在我的情况下,我附加的证书在pem格式中没有正确编码。如果使用keytools,请确保在从密钥库导出证书时附加-rfc,pem编码可以在文本编辑器中打开以显示:
-----BEGIN CERTIFICATE----- MIIDiDCCAnCgAwIBAgIEHKSkvDANBgkqhkiG9w0BAQsFADBi...

0

在使用 Go 中的 mysql 客户端时,我看到了相同的错误:

Failed to connect to database:  x509: cannot validate certificate for 10.111.202.229 because it doesn't contain any IP SANs

InsecureSkipVerify设置为true(跳过证书验证)解决了我的问题:

https://godoc.org/crypto/tls#Config

以下代码对我有效:
package main

import (
 "fmt"
 "github.com/go-sql-driver/mysql"
 "github.com/jinzhu/gorm"
 "crypto/tls"
 "crypto/x509"
 "io/ioutil"
 "log"
)

func main() {
    rootCertPool := x509.NewCertPool()
    pem, err := ioutil.ReadFile("/usr/local/share/ca-certificates/ccp-root-ca.crt")
    if err != nil {
            log.Fatal(err)
    }
    if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
        log.Fatal("Failed to append root CA cert at /usr/local/share/ca-certificates/ccp-root-ca.crt.")
    }
    mysql.RegisterTLSConfig("custom", &tls.Config{
        RootCAs: rootCertPool,
        InsecureSkipVerify: true,
    })

    db, err := gorm.Open("mysql", "ccp-user:I6qnD6zNDmqdDLXYg3HqVAk2P@tcp(10.111.202.229:3306)/ccp?tls=custom")
    defer db.Close()
}

-2

你需要使用InsecureSkipVerify标志,请参考https://groups.google.com/forum/#!topic/golang-nuts/c9zEiH6ixyw

此帖子的相关代码(以防页面离线):

smtpbox := "mail.foo.com:25"
c, err := smtp.Dial(smtpbox)

host, _, _ := net.SplitHostPort(smtpbox)
tlc := &tls.Config{
    InsecureSkipVerify: true,
    ServerName:         host,
}
if err = c.StartTLS(tlc); err != nil {
    fmt.Printf(err)
    os.Exit(1)
} 
// carry on with rest of smtp transaction 
// c.Auth, c.Mail, c.Rcpt, c.Data, etc

22
你应该验证 SSL 证书而不是仅接受任何 SSL 证书。 - Pwnna
8
这是一个重要的测试解决方案,对我的了解有很大帮助。谢谢! - jaten
2
InsecureSkipVerify 意味着“安全=关闭”。这会使您容易受到中间人攻击。这只适用于开发环境! - joonas.fi
开发测试的好选择。 - SunSparc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接