2016-11-03 35 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:未知的證書頒發機構錯誤,但這是另一個問題猜測。謝謝! –