本篇文章中,将描述如何使用go创建CA,并使用CA签署证书。在使用openssl创建证书时,遵循的步骤是 创建秘钥 > 创建CA > 生成要颁发证书的秘钥 > 使用CA签发证书。这种步骤,那么我们现在就来尝试下。

创建证书的颁发机构

首先,会从将从创建 CA 开始。CA 会被用来签署其他证书

// 对证书进行签名
ca := &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
CommonName: "domain name",
Organization: []string{"Company, INC."},
Country: []string{"US"},
Province: []string{""},
Locality: []string{"San Francisco"},
StreetAddress: []string{"Golden Gate Bridge"},
PostalCode: []string{"94016"},
},
NotBefore: time.Now(), // 生效时间
NotAfter: time.Now().AddDate(10, 0, 0), // 过期时间 年月日
IsCA: true, // 表示用于CA
// openssl 中的 extendedKeyUsage = clientAuth, serverAuth 字段
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
// openssl 中的 keyUsage 字段
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}

接下来需要对证书生成公钥和私钥

caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return err
}

然后生成证书:

caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey)
if err != nil {
return err
}

我们看到的证书内容是PEM编码后的,现在caBytes我们有了生成的证书,我们将其进行 PEM 编码以供以后使用:

caPEM := new(bytes.Buffer)
pem.Encode(caPEM, &pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
}) caPrivKeyPEM := new(bytes.Buffer)
pem.Encode(caPrivKeyPEM, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey),
})

创建证书

证书的 x509.Certificate 与CA的 x509.Certificate 属性有稍微不同,需要进行一些修改

cert := &x509.Certificate{
SerialNumber: big.NewInt(1658),
Subject: pkix.Name{
CommonName: "domain name",
Organization: []string{"Company, INC."},
Country: []string{"US"},
Province: []string{""},
Locality: []string{"San Francisco"},
StreetAddress: []string{"Golden Gate Bridge"},
PostalCode: []string{"94016"},
},
IPAddresses: []net.IP{}, // 这里就是openssl配置文件中 subjectAltName 里的 IP:/IP=
DNSNames: []string{}, // 这里就是openssl配置文件中 subjectAltName 里的 DNS:/DNS=
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
SubjectKeyId: []byte{1, 2, 3, 4, 6},
// 这里就是openssl中的extendedKeyUsage
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
}

注:这里会在证书中特别添加了 DNSIP (这个不是必须的),这个选项的增加代表的我们的证书可以支持多域名

为该证书创建私钥和公钥:

certPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return err
}

使用CA签署证书

有了上述的内容后,可以创建证书并用CA进行签名

certBytes, err := x509.CreateCertificate(rand.Reader, cert, ca, &certPrivKey.PublicKey, caPrivKey)
if err != nil {
return err
}

要保存成证书格式需要做PEM编码

certPEM := new(bytes.Buffer)
pem.Encode(certPEM, &pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
}) certPrivKeyPEM := new(bytes.Buffer)
pem.Encode(certPrivKeyPEM, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(certPrivKey),
})

把上面内容融合为一起

创建一个 ca.go 里面是创建ca和颁发证书的逻辑

package main

import (
"bytes"
cr "crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"math/rand"
"net"
"os"
"time"
) type CERT struct {
CERT []byte
CERTKEY *rsa.PrivateKey
CERTPEM *bytes.Buffer
CERTKEYPEM *bytes.Buffer
CSR *x509.Certificate
} func CreateCA(sub *pkix.Name, expire int) (*CERT, error) {
var (
ca = new(CERT)
err error
) if expire < 1 {
expire = 1
}
// 为ca生成私钥
ca.CERTKEY, err = rsa.GenerateKey(cr.Reader, 4096)
if err != nil {
return nil, err
} // 对证书进行签名
ca.CSR = &x509.Certificate{
SerialNumber: big.NewInt(rand.Int63n(2000)),
Subject: *sub,
NotBefore: time.Now(), // 生效时间
NotAfter: time.Now().AddDate(expire, 0, 0), // 过期时间
IsCA: true, // 表示用于CA
// openssl 中的 extendedKeyUsage = clientAuth, serverAuth 字段
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
// openssl 中的 keyUsage 字段
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}
// 创建证书
// caBytes 就是生成的证书
ca.CERT, err = x509.CreateCertificate(cr.Reader, ca.CSR, ca.CSR, &ca.CERTKEY.PublicKey, ca.CERTKEY)
if err != nil {
return nil, err
}
ca.CERTPEM = new(bytes.Buffer)
pem.Encode(ca.CERTPEM, &pem.Block{
Type: "CERTIFICATE",
Bytes: ca.CERT,
})
ca.CERTKEYPEM = new(bytes.Buffer)
pem.Encode(ca.CERTKEYPEM, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(ca.CERTKEY),
}) // 进行PEM编码,编码就是直接cat证书里面内容显示的东西
return ca, nil
} func Req(ca *x509.Certificate, sub *pkix.Name, expire int, dns []string, ip []net.IP) (*CERT, error) {
var (
cert = &CERT{}
err error
)
cert.CERTKEY, err = rsa.GenerateKey(cr.Reader, 4096)
if err != nil {
return nil, err
}
if expire < 1 {
expire = 1
}
cert.CSR = &x509.Certificate{
SerialNumber: big.NewInt(rand.Int63n(2000)),
Subject: *sub,
IPAddresses: ip,
DNSNames: dns,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(expire, 0, 0),
SubjectKeyId: []byte{1, 2, 3, 4, 6},
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
} cert.CERT, err = x509.CreateCertificate(cr.Reader, cert.CSR, ca, &cert.CERTKEY.PublicKey, cert.CERTKEY)
if err != nil {
return nil, err
} cert.CERTPEM = new(bytes.Buffer)
pem.Encode(cert.CERTPEM, &pem.Block{
Type: "CERTIFICATE",
Bytes: cert.CERT,
})
cert.CERTKEYPEM = new(bytes.Buffer)
pem.Encode(cert.CERTKEYPEM, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(cert.CERTKEY),
})
return cert, nil
} func Write(cert *CERT, file string) error {
keyFileName := file + ".key"
certFIleName := file + ".crt"
kf, err := os.Create(keyFileName)
if err != nil {
return err
}
defer kf.Close() if _, err := kf.Write(cert.CERTKEYPEM.Bytes()); err != nil {
return err
} cf, err := os.Create(certFIleName)
if err != nil {
return err
}
if _, err := cf.Write(cert.CERTPEM.Bytes()); err != nil {
return err
}
return nil
}

如果需要使用的话,可以引用这些函数

package main

import (
"crypto/x509/pkix"
"log"
"net"
) func main() {
subj := &pkix.Name{
CommonName: "chinamobile.com",
Organization: []string{"Company, INC."},
Country: []string{"US"},
Province: []string{""},
Locality: []string{"San Francisco"},
StreetAddress: []string{"Golden Gate Bridge"},
PostalCode: []string{"94016"},
}
ca, err := CreateCA(subj, 10)
if err != nil {
log.Panic(err)
} Write(ca, "./ca") crt, err := Req(ca.CSR, subj, 10, []string{"test.default.svc", "test"}, []net.IP{}) if err != nil {
log.Panic(err)
} Write(crt, "./tls")
}

遇到的问题

panic: x509: unsupported public key type: rsa.PublicKey

这里是因为 x509.CreateCertificate 的参数 privatekey 需要传入引用变量,而传入的是一个普通变量

注:x509: only RSA and ECDSA public keys supported

一些参数的意思

extendedKeyUsage :增强型密钥用法(参见"new_oids"字段):服务器身份验证、客户端身份验证、时间戳。

extendedKeyUsage = critical,serverAuth, clientAuth, timeStamping

keyUsage : 密钥用法,防否认(nonRepudiation)、数字签名(digitalSignature)、密钥加密(keyEncipherment)。

keyUsage = nonRepudiation, digitalSignature, keyEncipherment

Reference

golang ca and signed cert go

package x509

通过Go语言创建CA与签发证书的更多相关文章

  1. https学习笔记三----OpenSSL生成root CA及签发证书

    在https学习笔记二,已经弄清了数字证书的概念,组成和在https连接过程中,客户端是如何验证服务器端的证书的.这一章,主要介绍下如何使用openssl库来创建key file,以及生成root C ...

  2. OpenSSL生成root CA及签发证书

    一.openssl 简介 openssl 是目前最流行的 SSL 密码库工具,其提供了一个通用.健壮.功能完备的工具套件,用以支持SSL/TLS 协议的实现.官网:https://www.openss ...

  3. Centos7创建CA和申请证书

    转载:http://rackie386.blog.51cto.com/11279229/1947999 Centos7.3创建CA和申请证书 openssl 的配置文件:/etc/pki/tls/op ...

  4. Centos7创建CA和申请证书 转自https://www.cnblogs.com/mingzhang/p/8949541.html

    Centos7.3创建CA和申请证书 openssl 的配置文件:/etc/pki/tls/openssl.cnf 重要参数配置路径 dir   = /etc/pki/CA               ...

  5. IIS8中使用OpenSSL来创建CA并且签发SSL证书

    前言 [转载]http://alvinhu.com/blog/2013/06/12/creating-a-certificate-authority-and-signing-the-ssl-certi ...

  6. 创建私有CA并签发证书

    一.创建私有CA 1.创建所需要的文件 2.创建私有密钥 3.CA自签证书 -new: 生成新证书签署请求:               -x509: 专用于CA生成自签证书:不自签的时候不要加该选项 ...

  7. IIS10中使用OpenSSL来创建CA并且签发SSL证书

    参考: http://www.cnblogs.com/lierle/p/5140187.html http://alvinhu.com/blog/2013/06/12/creating-a-certi ...

  8. ssl证书专题(3):创建CA和申请证书

    请看:  https://www.cnblogs.com/mingzhang/p/8949541.html

  9. openssl CA 自签证书,阿里云配置tomcat https

    <一,openssl CA自签发证书> 1,生成私钥 openssl genrsa 1024 > private.key;

随机推荐

  1. 基于Kubernetes构建企业Jenkins master/slave CI/CD平台

    搭建平台目的: k8s中搭建jenkins master/slave架构,解决单jenkins执行效率低,资源不足等问题(jenkins master 调度任务到 slave上,并发执行任务,提升任务 ...

  2. ArcGIS使用技巧(一)——数据存储

    新手,若有错误还请指正! 日常接触ArcGIS较多,发现好多人虽然也在用ArcGIS,但一些基础的小技巧并不知道,写下来希望对大家有所帮助. ArcGIS默认的存储数据库是在C盘(图1),不修改存储数 ...

  3. docker入门_docker安装

    docker入门_docker安装 ubuntu 安装 curl -sSL https://get.daocloud.io/docker | sh # 官方安装脚本自动安装 systemctl ena ...

  4. hibernate查询不到关联对象列表-fetchType的选择

    概述 昨天排查问题的时候,发现使用hibernate关联对象时,订单实体类对象死活无法获取关联的订单明细列表 Order order = orderDao.findById(201L); //明明数据 ...

  5. OA办公软件篇(三)—审批流

    背景 作用 迭代历程 具体实现 写在最后   背景 在前面两篇文章中,我们分别讲了组织架构和权限管理,今天我们来讲一个跟组织架构关系比较密切的功能-审批流. 审批流,通俗来说就是一个完整的审批流程,是 ...

  6. Python技法:用re模块实现简易tokenizer

    一个简单的tokenizer 分词(tokenization)任务是Python字符串处理中最为常见任务了.我们这里讲解用正则表达式构建简单的表达式分词器(tokenizer),它能够将表达式字符串从 ...

  7. 一文彻底搞懂MySQL分区

    一个执着于技术的公众号 一.InnoDB逻辑存储结构 首先要先介绍一下InnoDB逻辑存储结构和区的概念,它的所有数据都被逻辑地存放在表空间,表空间又由段,区,页组成. 段 段就是上图的segment ...

  8. 【python疫情可视化】用pyecharts开发全国疫情动态地图,效果酷炫!

    一.效果演示 我用python开发了一个动态疫情地图,首先看下效果: 如图所示,地图根据实时数据通过时间线轮播的方式,动态展示数据的变化.随着时间的推移,疫情确诊数量的增多,地图各个省份颜色逐渐加深, ...

  9. Debouncer防抖代码

    Debouncer类 import java.util.concurrent.*; public class Debouncer { private final ScheduledExecutorSe ...

  10. 安装Siege到Linux(源码)

    运行环境 系统版本:CentOS Linux release 7.3.1611 (Core) 软件版本:siege-4.0.4 硬件要求:无 安装过程 1.安装依赖 [root@localhost ~ ...