前言数字证书是由证书颁发机构数字签名的文件,包含公钥所有者和公钥的信息。证书颁发涉及到非对称加密的知识。这里介绍使用golang中的x509标准库进行证书自发,以及证书颁发后如何使用golang进行双向认证。自签名证书生成的根证书由CA认证中心给出。我们自己颁发的证书是信任链的起点。这里我们使用openssl命令生成根证书。先生成私钥opensslgenrsa-outkey.pem2048然后根据私钥提取公钥opensslrsa-inkey。pem-pubout-outkey.pub开始生成X509格式的自签名证书,会要求输入识别名DN的信息(国家、城市、组织、姓名、邮箱等)pensslreq-x509-new-days365-keyrsakey.pem-outcert.crt到这里根证书就准备好了,接下来就是使用golang根据根证书颁发下一级证书,使用golang自签名证书关于自签名证书的流程,这里简单介绍一下,golangx509标准库下有一个Certificate结构,就是证书解析后对应的实体,新证书需要生成秘钥对,然后使用根证书的私钥进行签名,证书、私钥和公钥都是pem编码方式,首先读取根证书的证书和私钥//解析根证书caFile,err:=ioutil.ReadFile(rootCa)iferr!=nil{return}caBlock,_:=pem.Decode(caFile)cert,err:=x509.ParseCertificate(caBlock.Bytes)iferr!=nil{return}//解析私钥keyFile,err:=ioutil.ReadFile(rootKey)iferr!=nil{return}keyBlock,_:=pem.解码(keyFile)praKey,错误:=x509.ParsePKCS1PrivateKey(keyBlock.Bytes)iferr!=nil{return}然后需要生成新的证书模板,根据自己的需要填写字段,cer:=&x509.Certificate{SerialNumber:big.NewInt(rd.Int63()),//证书序列号Subject:pkix.Name{Country:[]string{"CN"},Organization:[]string{"Easy"},OrganizationalUnit:[]string{"Easy"},Province:[]string{"ShenZhen"},CommonName:equi.Code,Locality:[]string{"ShenZhen"},},NotBefore:time.Now(),//证书有效期开始时间NotAfter:time.Now().AddDate(1,0,0),//证书有效期结束时间BasicConstraintsValid:true,//基本有效性约束IsCA:false,//是否为根证书ExtKeyUsage:[]x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth,x509.ExtKeyUsageServerAuth},//CertificatePurpose(客户端认证,数据加密)KeyUsage:x509.KeyUsag电子数字签名|x509.KeyUsageDataEncipherment,EmailAddresses:[]string{"test@test.com"},IPAddresses:[]net.IP{net.ParseIP("192.168.1.59")},}获取到该信息后,将证书可以颁发,key和ca是颁发的证书和私钥。//生成公私钥对priKey,err:=rsa.GenerateKey(rand.Reader,2048)iferr!=nil{return}ca,err=x509.CreateCertificate(rand.Reader,equiCer,rootCa,&priKey.PublicKey,rootKey)iferr!=nil{return}//编码证书文件和私钥文件caPem:=&pem.Block{Type:"CERTIFICATE",Bytes:ca,}ca=pem.EncodeToMemory(caPem)buf:=x509.MarshalPKCS1PrivateKey(priKey)keyPem:=&pem.Block{Type:"PRIVATEKEY",Bytes:buf,}key=pem.EncodeToMemory(keyPem)使用golang进行双向身份验证客户端//加载客户端证书//这里是服务器颁发的证书,err:=tls.LoadX509KeyPair("client_cert.pem","client_key.pem")iferr!=nil{log.Fatalln(err)}config:=&tls.Config{//不要在这里验证服务器证书,是的InsecureSkipVerify:true,证书:[]tls.Certificate{cert},}raddr,err:=net.ResolveTCPAdr("tcp","192.168.1.59:6001")iferr!=nil{log.Fatalln(err)}conn,err:=net.DialTCP("tcp",nil,raddr)iferr!=nil{log.Fatalln(err)}tlsConn:=tls.Client(conn,config)tlsConn就像net.康恩是一样的。当Wirte被调用时,它会握手。如果服务器证书不符合要求,则会返回错误。Server//这里是根证书buf,err:=ioutil.ReadFile(d.conf.Tls.CA)iferr!=nil{return}pool:=x509.NewCertPool()pool.AppendCertsFromPEM(buf)//load服务器证书cert,err:=tls.LoadX509KeyPair(d.conf.Tls.Cert,d.conf.Tls.Key)iferr!=nil{return}tlsConfig:=&tls.ConfigCertificates:[]tls.Certificate{cert},ClientAuth:tls.RequireAndVerifyClientCert,ClientCAs:pool,}//accepttoconnaftertlsConn:=tls.Server(conn,tlsConfig)这个tlsConn和client的一样,也可以手动调用Handshake来摇手。结语这里只是简单介绍一下,关于证书知识不止于此。比如x509标准库还可以生成证书签发请求,解析证书吊销列表等,多多练习可以帮助你更深入地理解证书知识。
