2016-11-03 190 views
2

我试图弄清楚如何我可以实现一个函数,饲养tls.Config.GetCertificate与自签名证书。执行tls.Config.GetCertificate与自签名证书

我用这个彬源为基础,https://golang.org/src/crypto/tls/generate_cert.go

而且阅读, https://ericchiang.github.io/tls/go/https/2015/06/21/go-tls.html

遗憾的是,到目前为止,即时通讯坚持这个错误 2016/11/03 23:18:20 http2: server: error reading preface from client 127.0.0.1:34346: remote error: tls: unknown certificate authority

我想我需要生成一个CA证书,然后用它签署密钥,但我不知道如何继续(....)。

这是我的代码,有人可以帮助吗?

package gssc 

import (
    "crypto/rand" 
    "crypto/rsa" 
    "crypto/tls" 
    "crypto/x509" 
    "crypto/x509/pkix" 
    "github.com/pkg/errors" 
    "math/big" 
    "net" 
    "strings" 
    "time" 
) 

func GetCertificate(arg interface{}) func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { 
    var opts Certopts 
    var err error 
    if host, ok := arg.(string); ok { 
     opts = Certopts{ 
      RsaBits: 2048, 
      Host:  host, 
      ValidFrom: time.Now(), 
     } 
    } else if o, ok := arg.(Certopts); ok { 
     opts = o 
    } else { 
     err = errors.New("Invalid arg type, must be string(hostname) or Certopt{...}") 
    } 
    return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { 
     if err != nil { 
      return nil, err 
     } 
     return generate(opts) 
    } 
} 

type Certopts struct { 
    RsaBits int 
    Host  string 
    IsCA  bool 
    ValidFrom time.Time 
    ValidFor time.Duration 
} 

func generate(opts Certopts) (*tls.Certificate, error) { 

    priv, err := rsa.GenerateKey(rand.Reader, opts.RsaBits) 
    if err != nil { 
     return nil, errors.Wrap(err, "failed to generate private key") 
    } 

    notAfter := opts.ValidFrom.Add(opts.ValidFor) 

    serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 
    serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 
    if err != nil { 
     return nil, errors.Wrap(err, "Failed to generate serial number\n") 
    } 

    template := x509.Certificate{ 
     SerialNumber: serialNumber, 
     Subject: pkix.Name{ 
      Organization: []string{"Acme Co"}, 
     }, 
     NotBefore: opts.ValidFrom, 
     NotAfter: notAfter, 

     KeyUsage:    x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 
     ExtKeyUsage:   []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 
     BasicConstraintsValid: true, 
    } 

    hosts := strings.Split(opts.Host, ",") 
    for _, h := range hosts { 
     if ip := net.ParseIP(h); ip != nil { 
      template.IPAddresses = append(template.IPAddresses, ip) 
     } else { 
      template.DNSNames = append(template.DNSNames, h) 
     } 
    } 

    if opts.IsCA { 
     template.IsCA = true 
     template.KeyUsage |= x509.KeyUsageCertSign 
    } 

    derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) 
    if err != nil { 
     return nil, errors.Wrap(err, "Failed to create certificate") 
    } 

    return &tls.Certificate{ 
     Certificate: [][]byte{derBytes}, 
     PrivateKey: priv, 
    }, nil 
} 

这是测试代码,我使用

package main 

import (
    "crypto/tls" 
    "github.com/mh-cbon/gssc" 
    "net/http" 
) 

type ww struct{} 

func (s *ww) ServeHTTP(w http.ResponseWriter, req *http.Request) { 
    w.Header().Set("Content-Type", "text/plain") 
    w.Write([]byte("This is an example server.\n")) 
} 

func main() { 
    s := &http.Server{ 
     Handler: &ww{}, 
     Addr: ":8080", 
     TLSConfig: &tls.Config{ 
      InsecureSkipVerify: true, 
      GetCertificate:  gssc.GetCertificate("example.org"), 
     }, 
    } 
    s.ListenAndServeTLS("", "") 

} 

非常感谢!

+0

是否有你不使用'去fmt'理由吗? –

回答

2

您的tls.Config.GetCertificate的实施导致了这个问题。

您每次调用tls.Config.GetCertificate时都会生成证书。您需要生成一次证书,然后在匿名函数中返回。

gssc.GetCertificate

cert, err := generate(opts) 

return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { 
     if err != nil { 
      return nil, err 
     } 
     return cert, err 
    } 
+0

嗨,感谢您的反馈,真的很感激,不幸的是,它确实没有帮助我,因为我以前没有使用该代码来创建[二进制](https://github.com/mh-cbon/sscg)工具生成这些证书纯文件,所以我知道它工作。我真的希望以[this](https://godoc.org/golang.org/x/crypto/acme/autocert)的相同方式实现这个GetCert方法。也许我应该在我原来的帖子中精简。 –

+1

已更新。我猜这是问题。 –

+0

是啊!我现在看到了这个问题,我每次都会生成一个新的证书,以便在随后的请求进入时浏览器正在混合。我仍然有错误'2016/11/09 11:18:36 http2:服务器:从客户端读取前言127.0.0.1:41748:远程错误:tls:未知的证书颁发机构错误,但这是另一个问题猜测。谢谢! –