生成一个 x.509 证书
/**
生成自签名 X.509 证书并保存到一个.cer 文件中(自签名证书通常不会被浏览器信任
**/
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/gob"
"encoding/pem"
"fmt"
"math/big"
"os"
"time"
)
func main() {
random := rand.Reader
// var key rsa.PrivateKey
// 使用指定 RSA 密钥
// loadKey("private.key", &key)
// 随机生成一对具有指定字位数的RSA密钥
key, _ := rsa.GenerateKey(rand.Reader, 2048)
now := time.Now()
then := now.Add(60 * 60 * 24 * 365 * 1000 * 1000 * 1000)
// 创建证书模版
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name {
CommonName: "jan.newmarch.name",
Organization: []string{"Jan Newmarch"},
},
NotBefore: now,
NotAfter: then,
SubjectKeyId: []byte{1,2,3,4},
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
BasicConstraintsValid: true,
IsCA: true,
DNSNames: []string{"jan.newmarch.name", "localhost"},
}
// 创建证书
derBytes, err := x509.CreateCertificate(random, &template, &template, &key.PublicKey, key)
checkError(err)
// 创建一个文件用于存储证书
certCerFile, err := os.Create("jan.newmarch.name.cer")
defer certCerFile.Close()
checkError(err)
// 将证书写入文件中
certCerFile.Write(derBytes)
// 将证书转成pem文件
// 创建一个pem文件
certPEMFile, err := os.Create("jan.newmarch.name.pem")
defer certPEMFile.Close()
checkError(err)
pem.Encode(certPEMFile, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
// 将密钥转pem文件
// 创建一个pem文件
keyPEMFile, err := os.Create("private.pem")
defer keyPEMFile.Close()
checkError(err)
pem.Encode(keyPEMFile, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
}
func loadKey(fileName string, key interface{}) {
inFile, err := os.Open(fileName)
defer inFile.Close()
checkError(err)
decoder := gob.NewDecoder(inFile)
// 将文件中的数据解码到 key 中
err = decoder.Decode(key)
checkError(err)
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error", err.Error())
os.Exit(1)
}
}
读取证书文件中的证书
/**
读取 jan.newmarch.name.cer 中的证书
**/
package main
import (
"crypto/x509"
"fmt"
"os"
)
func main() {
certCerFile, err := os.Open("jan.newmarch.name.cer")
defer certCerFile.Close()
checkError(err)
derBytes := make([]byte, 1000)
count, err := certCerFile.Read(derBytes)
checkError(err)
cert, err := x509.ParseCertificate(derBytes[0:count])
checkError(err)
fmt.Printf("Name %s\n", cert.Subject.CommonName)
fmt.Printf("Not before %s\n", cert.NotBefore.String())
fmt.Printf("Not after %s\n", cert.NotAfter.String())
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error", err.Error())
os.Exit(1)
}
}
tcp 服务端使用证书
可以参考博客: https://www.jianshu.com/p/4cf92c5a386d
server.go
/**
tls 加密服务程序
**/
package main
import (
"crypto/rand"
"crypto/tls"
"fmt"
"net"
"os"
"time"
)
func main() {
cert, err := tls.LoadX509KeyPair("jan.newmarch.name.pem", "private.pem")
checkError(err)
config := tls.Config{Certificates: []tls.Certificate{cert}}
now := time.Now()
config.Time = func() time.Time {
return now
}
config.Rand = rand.Reader
service := "0.0.0.0:1200"
listener, err := tls.Listen("tcp", service, &config)
checkError(err)
fmt.Println("Listening")
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println(err.Error())
continue
}
fmt.Println("Accepted")
go handleClient(conn)
}
}
func handleClient(conn net.Conn) {
defer conn.Close()
var buf[512]byte
for {
fmt.Println("Trying to read")
n, err := conn.Read(buf[0:])
if err != nil {
fmt.Println(err)
return
}
_, err2 := conn.Write(buf[0:n])
if err2 != nil {
return
}
}
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error", err.Error())
os.Exit(1)
}
}
对应的 client.go
/**
tls 加密服客户程序
**/
package main
import (
"fmt"
"os"
"crypto/tls"
)
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: ", os.Args[0], "host:port")
os.Exit(1)
}
// InsecureSkipVerify用来控制客户端是否证书和服务器主机名一致。如果设置为true,则不会校验证书以及证书中的主机名和服务器主机名是否一致
// 因为在我们的例子中使用自签名的证书,所以设置它为true,仅仅用于测试目的
conf := &tls.Config{
InsecureSkipVerify: true,
}
service := os.Args[1]
// 生成 tcp 报文
conn, err := tls.Dial("tcp", service, conf)
checkError(err)
for i := 0; i < 10; i++ {
fmt.Println("writing...")
conn.Write([]byte("Hello " + string(i + 48)))
var buf [512]byte
n, err := conn.Read(buf[0:])
checkError(err)
fmt.Println(string(buf[0:n]))
}
os.Exit(0)
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error", err.Error())
os.Exit(1)
}
}