用golang生成密钥和签名证书
go version:
$ go version
go version go1.10 darwin/amd64
注意每个代码片段里的变量,在全文里是共用的。比如第一步里生成的私钥,在后面签名将直接拿来使用。
生成ECDSA密钥
type ecdsaGen struct {
curve elliptic.Curve
}
func (e *ecdsaGen) KeyGen() (key *ecdsa.PrivateKey, err error) {
privKey, err := ecdsa.GenerateKey(e.curve, rand.Reader)
if err != nil {
return nil, err
}
return privKey, nil
}
func checkError(err error) {
if err != nil {
log.Panic(err)
}
}
func main() {
// 生成ecdsa
e := &ecdsaGen{ curve: elliptic.P256()}
priKey, err := e.KeyGen()
checkError(err)
}
priKey
是我们生成的密钥,有时候我们想保存为一个pem格式的密钥文件:
priKeyEncode, err := x509.MarshalECPrivateKey(priKey)
checkError(err)
f, err := os.Create("ec.pem")
checkError(err)
pem.Encode(f, &pem.Block{Type: "EC PRIVATE KEY", Bytes: priKeyEncode})
f.close()
经过x509.MarshalECPrivateKey
处理过后返回的是[]byte类型的密钥,然后通过pem.Encode
写入到文件里。
然后我们可以用:$ openssl ec -text -in ec.pem -noout
命令来查看生成的密钥文件是否正确,后面同样有可以用openssl来检查生成的证书是否正确。
更多openssl
命令可以查看openssl常用命令之创建、检查密钥和证书。
证书
这里举两个例子,一个是用自己的密钥进行为证书签名,简称自签。还有一种现实中经常遇到的情况,是使用用户提供的密钥生成证书。
自签
// 根据ecdsa密钥生成特征标识码
func priKeyHash(priKey *ecdsa.PrivateKey) []byte{
hash := sha256.New()
hash.Write(elliptic.Marshal(priKey.Curve, priKey.PublicKey.X, priKey.PublicKey.Y))
return hash.Sum(nil)
}
func main() {
template := x509.Certificate{
SerialNumber: serialNumber,
NotBefore: notBefore,
NotAfter: notBefore.Add(expiry).UTC(),
BasicConstraintsValid: true,
IsCA: true,
KeyUsage: x509.KeyUsageDigitalSignature |
x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign |
x509.KeyUsageCRLSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
Subject: pkix.Name{
Country: []string{"CN"},
Locality: []string{"zhongguancun"},
Province: []string{"Beijing"},
OrganizationalUnit: []string{"tect"},
Organization: []string{"paradise"},
StreetAddress: []string{"street", "address", "demo"},
PostalCode: []string{"310000"},
CommonName: "demo.example.com",
},
}
template.SubjectKeyId = priKeyHash(priKey)
x509certEncode, err := x509.CreateCertificate(rand.Reader, &template, &template, pubKey, priKey)
checkError(err)
crt, err := os.Create("cert.crt")
checkError(err)
pem.Encode(crt, &pem.Block{Type: "CERTIFICATE", Bytes: x509certEncode})
crt.Close()
}
先生成x509的证书模板,然后通过x509.CreateCertificate
创建证书,看下这个函数的定义:
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
...
}
当参数template
和parent
一样时,即为自签,代码最后将证书保存为cert.crt
。
如果想用openssl
命令自签请参考:创建证书(自签名)
使用用户提供的密钥生成证书
我们假设有个bob,想让我们为他的密钥提供证书签名:
func main() {
// 使用bob的密钥进行证书签名
bobPriKey, _ := e.KeyGen()
bobPriKeyEncode, err := x509.MarshalECPrivateKey(bobPriKey)
checkError(err)
bobf, err := os.Create("bob.pem")
checkError(err)
pem.Encode(bobf, &pem.Block{Type: "EC PRIVATE KEY", Bytes: bobPriKeyEncode})
bobf.Close()
bobPubKey := bobPriKey.Public()
bobSerialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
notBefore = time.Now().Add(-5 * time.Minute).UTC()
bobTemplate := x509.Certificate{
SerialNumber: bobSerialNumber,
NotBefore: notBefore,
NotAfter: notBefore.Add(expiry).UTC(),
BasicConstraintsValid: true,
IsCA: false,
KeyUsage: x509.KeyUsageDigitalSignature |
x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign |
x509.KeyUsageCRLSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
Subject: pkix.Name{
Country: []string{"CN"},
Locality: []string{"Locality"},
Province: []string{"Beijing"},
OrganizationalUnit: []string{"tect"},
Organization: []string{"paradise"},
StreetAddress: []string{"street", "address", "demo"},
PostalCode: []string{"310000"},
CommonName: "demo.example.com",
},
}
bobTemplate.SubjectKeyId = priKeyHash(bobPriKey)
parent, err := x509.ParseCertificate(x509certEncode)
checkError(err)
// 这里的第三个参数是我们上面自签的证书,公钥是bob的公钥
bobCertEncode, err := x509.CreateCertificate(rand.Reader, &bobTemplate, parent, bobPubKey, priKey)
checkError(err)
bcrt, _ := os.Create("bob.crt")
pem.Encode(bcrt, &pem.Block{Type: "CERTIFICATE", Bytes: bobCertEncode})
bcrt.close()
}
代码和自签差不多,要注意的是这一句代码:
// 这里的第三个参数是我们上面自签的证书,公钥是bob的公钥
bobCertEncode, err := x509.CreateCertificate(rand.Reader, &bobTemplate, parent, bobPubKey, priKey)
最后附上全文代码:Gist !
ft_authoradmin ft_create_time2020-11-09 16:01
ft_update_time2020-11-09 16:01
ft_update_time2020-11-09 16:01