doubo1871 2016-11-03 22:25
浏览 430
已采纳

使用自签名证书实现tls.Config.GetCertificate

I m trying to figure out how i can implement a function to feed to tls.Config.GetCertificate with self signed certificates.

I used this bin source as a base, https://golang.org/src/crypto/tls/generate_cert.go

Also read this, https://ericchiang.github.io/tls/go/https/2015/06/21/go-tls.html

Unfortunately, so far i m stuck with this error 2016/11/03 23:18:20 http2: server: error reading preface from client 127.0.0.1:34346: remote error: tls: unknown certificate authority

I think i need to generate a CA cert and then sign the key with it, but i m not sure how to proceed (....).

Here is my code, can someone help with that ?

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
")
    }

    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
}

This is the test code i use

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.
"))
}

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

}

Thanks a lot!

  • 写回答

1条回答 默认 最新

  • douza19870617 2016-11-08 13:19
    关注

    Your implementation of tls.Config.GetCertificate is causing the problem.

    You are generating a certificate each time tls.Config.GetCertificate is called. You need to generate the certificate once and then return it in the anonymous function.

    In gssc.GetCertificate :

    cert, err := generate(opts)
    
    return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
            if err != nil {
                return nil, err
            }
            return cert, err
        }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 pnpm 下载element-plus
  • ¥15 解决编写PyDracula时遇到的问题
  • ¥15 有没有人能解决下这个问题吗,本人不会编程
  • ¥15 plotBAPC画图出错
  • ¥30 关于#opencv#的问题:使用大疆无人机拍摄水稻田间图像,拼接成tif图片,用什么方法可以识别并框选出水稻作物行
  • ¥15 Python卡尔曼滤波融合
  • ¥20 iOS绕地区网络检测
  • ¥15 python验证码滑块图像识别
  • ¥15 根据背景及设计要求撰写设计报告
  • ¥20 能提供一下思路或者代码吗