gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/lib/gmsigner.go (about) 1 package lib 2 3 import ( 4 "crypto" 5 "crypto/rand" 6 "crypto/x509/pkix" 7 "encoding/asn1" 8 "encoding/hex" 9 "encoding/pem" 10 "fmt" 11 "io" 12 "math/big" 13 "net" 14 "net/mail" 15 "time" 16 17 "gitee.com/zhaochuninhefei/cfssl-gm/certdb" 18 "gitee.com/zhaochuninhefei/cfssl-gm/csr" 19 "gitee.com/zhaochuninhefei/cfssl-gm/signer" 20 "gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/util" 21 "gitee.com/zhaochuninhefei/fabric-gm/bccsp" 22 "gitee.com/zhaochuninhefei/fabric-gm/bccsp/sw" 23 "gitee.com/zhaochuninhefei/gmgo/sm2" 24 "gitee.com/zhaochuninhefei/gmgo/x509" 25 "gitee.com/zhaochuninhefei/zcgolog/zclog" 26 "github.com/pkg/errors" 27 ) 28 29 // 使用CA作为签署者生成x509证书 30 // 31 // Deprecated: 国密证书的签署改为使用`gitee.com/zhaochuninhefei/cfssl-gm` 32 func createCertByCA(req signer.SignRequest, ca *CA) (cert []byte, err error) { 33 // zclog.Debugf("===== CA服务端开始做证书签名") 34 // zclog.Debugf("===== req : %#v\n", req.Subject) 35 // 注意,这里只把 req.Request 转为pem,丢掉了 req.Subject 信息 36 block, _ := pem.Decode([]byte(req.Request)) 37 if block == nil { 38 return nil, errors.Errorf("decode error") 39 } 40 if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" { 41 return nil, errors.Errorf("not a csr") 42 } 43 // 基于req.Request(证书请求csr)生成证书模板 44 template, err := createCertTemplateByCertificateRequest(block.Bytes) 45 if err != nil { 46 zclog.Errorf("===== createCertTemplateByCertificateRequest error:[%s]", err) 47 return nil, err 48 } 49 // 补充OU与证书期限 50 err = fillOUAndNotAfter(template, req) 51 if err != nil { 52 zclog.Errorf("===== fillOUAndNotAfter error:[%s]", err) 53 return nil, err 54 } 55 // 获取CA证书路径 56 caCertFile := ca.Config.CA.Certfile 57 //certfile := req.Profile 58 // zclog.Debugf("===== certifle = %s", certfile) 59 // 读取CA证书文件,获取CA的私钥与其x509证书 60 caRootkey, _, caRootCert, err := util.GetSignerFromCertFile(caCertFile, ca.csp) 61 if err != nil { 62 return nil, err 63 } 64 // zclog.Debugf("===== rootca = %v", rootca) 65 // rootca := ParseX509Certificate2Sm2(x509cert) 66 // 使用CA的私钥与其x509证书给template签名,生成对应证书,并转为pem字节数组 67 cert, err = sw.CreateCertificateToMem(template, caRootCert, caRootkey) 68 if err != nil { 69 return nil, err 70 } 71 // zclog.Debugf("===== template = %v\n Type = %T", template, template.PublicKey) 72 // 将pem字节数组转为x509证书 73 clientCert, err := x509.ReadCertificateFromPem(cert) 74 if err != nil { 75 return nil, err 76 } 77 // zclog.Debugf("===== template.SerialNumber---,%v", template.SerialNumber) 78 // zclog.Debugf("===== clientCert--,%v", clientCert) 79 // zclog.Debugf("===== cert--,%v", cert) 80 // zclog.Debugf("===== req.Label--,%v", req.Label) 81 // zclog.Debugf("===== clientCert.NotAfter--,%v", clientCert.NotAfter) 82 // zclog.Debug("===== Exit ParseCertificate") 83 zclog.Debugf("===== 生成的证书长度 [%d]", len(cert)) 84 // 将生成的证书插入DB 85 var certRecord = certdb.CertificateRecord{ 86 Serial: template.SerialNumber.String(), 87 AKI: hex.EncodeToString(clientCert.AuthorityKeyId), 88 CALabel: req.Label, 89 Status: "good", 90 Expiry: clientCert.NotAfter, 91 PEM: string(cert), 92 } 93 //aki := hex.EncodeToString(cert.AuthorityKeyId) 94 //serial := util.GetSerialAsHex(cert.SerialNumber) 95 err = ca.certDBAccessor.InsertCertificate(certRecord) 96 if err != nil { 97 zclog.Errorf("===== error InsertCertificate:[%s]", err) 98 } 99 return 100 } 101 102 // 生成自签名的CA根证书 103 // 104 // Deprecated: 国密证书的签署改为使用`gitee.com/zhaochuninhefei/cfssl-gm` 105 func createRootCACert(key bccsp.Key, req *csr.CertificateRequest, priv crypto.Signer) (cert []byte, err error) { 106 zclog.Debugf("===== key类型 :%T", key) 107 // 生成标准的国密x509证书请求 108 csrPEM, err := createCertificateRequest(priv, req, key) 109 if err != nil { 110 zclog.Errorf("===== createCertificateRequest error:%s", err) 111 return nil, err 112 } 113 block, _ := pem.Decode(csrPEM) 114 if block == nil { 115 return nil, errors.Errorf("===== lib/gmca.go createRootCACert sm2 csr DecodeFailed") 116 } 117 118 if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" { 119 return nil, errors.Errorf("===== lib/gmca.go createRootCACert sm2 not a csr") 120 } 121 // 根据证书请求生成x509证书模板,需要补充证书期限信息 122 certTemplate, err := createCertTemplateByCertificateRequest(block.Bytes) 123 if err != nil { 124 return nil, err 125 } 126 // 补充模板的证书期限 127 certTemplate.NotBefore = time.Now() 128 // 作为CA自签名的根证书,使用期限最长的 defaultRootCACertificateExpiration 129 certTemplate.NotAfter = time.Now().Add(parseDuration(defaultRootCACertificateExpiration)) 130 // 生成自签名的CA根证书 131 cert, err = sw.CreateCertificateToMem(certTemplate, certTemplate, key) 132 return 133 } 134 135 // 补充OU信息 136 // 137 // Deprecated: 国密证书的签署改为使用`gitee.com/zhaochuninhefei/cfssl-gm` 138 func fillOUAndNotAfter(template *x509.Certificate, req signer.SignRequest) error { 139 subject := req.Subject 140 // zclog.Debugf("===== before template.Subject: %#v , subject: %#v", template.Subject, subject) 141 if len(subject.Names) > 0 { 142 if len(template.Subject.OrganizationalUnit) == 0 { 143 var tmpOUs []string 144 for _, csrName := range subject.Names { 145 if csrName.OU != "" { 146 tmpOUs = append(tmpOUs, csrName.OU) 147 } 148 } 149 template.Subject.OrganizationalUnit = tmpOUs 150 } else { 151 tmpOUs := template.Subject.OrganizationalUnit 152 for _, csrName := range subject.Names { 153 ouAdd := csrName.OU 154 if ouAdd == "" { 155 continue 156 } 157 needAdd := true 158 for _, ouExist := range tmpOUs { 159 if ouAdd == ouExist { 160 needAdd = false 161 break 162 } 163 } 164 if needAdd { 165 tmpOUs = append(tmpOUs, ouAdd) 166 } 167 } 168 template.Subject.OrganizationalUnit = tmpOUs 169 } 170 } 171 // zclog.Debugf("===== after template.Subject: %#v , subject: %#v", template.Subject, subject) 172 template.NotBefore = time.Now() 173 // zclog.Debugf("===== req.NotAfter: %s", req.NotAfter.Format(time.RFC3339)) 174 if req.NotAfter.IsZero() { 175 template.NotAfter = time.Now().Add(defaultIssuedCertificateExpiration) 176 } else { 177 template.NotAfter = req.NotAfter 178 } 179 // zclog.Debugf("===== template.NotAfter: %s", template.NotAfter.Format(time.RFC3339)) 180 return nil 181 } 182 183 // 根据证书请求生成x509证书模板 184 // 注意,生成的模板缺少证书期限,缺少扩展信息 185 // 186 // Deprecated: 国密证书的签署改为使用`gitee.com/zhaochuninhefei/cfssl-gm` 187 func createCertTemplateByCertificateRequest(csrBytes []byte) (template *x509.Certificate, err error) { 188 csrv, err := x509.ParseCertificateRequest(csrBytes) 189 if err != nil { 190 return nil, err 191 } 192 err = csrv.CheckSignature() 193 if err != nil { 194 return nil, err 195 } 196 // zclog.Debugf("===== csrv :%#v", csrv) 197 template = &x509.Certificate{ 198 Subject: csrv.Subject, 199 PublicKeyAlgorithm: csrv.PublicKeyAlgorithm, 200 PublicKey: csrv.PublicKey, 201 SignatureAlgorithm: csrv.SignatureAlgorithm, 202 DNSNames: csrv.DNSNames, 203 IPAddresses: csrv.IPAddresses, 204 EmailAddresses: csrv.EmailAddresses, 205 } 206 // zclog.Debugf("===== algorithn = %v, %v\n", template.PublicKeyAlgorithm, template.SignatureAlgorithm) 207 // zclog.Debugf("===== publicKey :%T", template.PublicKey) 208 209 for _, val := range csrv.Extensions { 210 zclog.Debugf("===== csrv.Extensions: %s", val) 211 // Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9) 212 // extension and append to template if necessary 213 if val.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) { 214 zclog.Debug("===== csrv.Extensions 有 ca constraints信息") 215 var constraints csr.BasicConstraints 216 // var rest []byte 217 // if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil { 218 // //return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) 219 // } else if len(rest) != 0 { 220 // //return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, errors.New("x509: trailing data after X.509 BasicConstraints")) 221 // } 222 asn1.Unmarshal(val.Value, &constraints) 223 224 template.BasicConstraintsValid = true 225 template.IsCA = constraints.IsCA 226 template.MaxPathLen = constraints.MaxPathLen 227 template.MaxPathLenZero = template.MaxPathLen == 0 228 } 229 } 230 serialNumber := make([]byte, 20) 231 _, err = io.ReadFull(rand.Reader, serialNumber) 232 if err != nil { 233 return nil, err 234 } 235 236 // SetBytes interprets buf as the bytes of a big-endian 237 // unsigned integer. The leading byte should be masked 238 // off to ensure it isn't negative. 239 serialNumber[0] &= 0x7F 240 241 template.SerialNumber = new(big.Int).SetBytes(serialNumber) 242 243 return 244 } 245 246 // 生成标准的国密x509证书请求 247 // 248 // Deprecated: 国密证书的签署改为使用`gitee.com/zhaochuninhefei/cfssl-gm` 249 func createCertificateRequest(priv crypto.Signer, req *csr.CertificateRequest, key bccsp.Key) (csr []byte, err error) { 250 sigAlgo := signerAlgo(priv) 251 if sigAlgo == x509.UnknownSignatureAlgorithm { 252 return nil, errors.Errorf("===== lib/gmca.go generate Private key type is unsupported") 253 } 254 // zclog.Debug("===== begin create sm2.CertificateRequest") 255 reqName := req.Name() 256 // 生成证书申请模板 257 var tpl = x509.CertificateRequest{ 258 Subject: reqName, 259 SignatureAlgorithm: sigAlgo, 260 } 261 // 根据req.Hosts补充SAN字段 优先顺序 IP > EMail > DNS 262 for i := range req.Hosts { 263 if ip := net.ParseIP(req.Hosts[i]); ip != nil { 264 tpl.IPAddresses = append(tpl.IPAddresses, ip) 265 } else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil { 266 tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address) 267 } else { 268 tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) 269 } 270 } 271 // 请求CA证书时,补充BasicConstraints信息 272 if req.CA != nil { 273 err = appendCAInfoToCSR(req.CA, &tpl) 274 if err != nil { 275 err = fmt.Errorf("===== lib/gmca.go createCertificateRequest appendCAInfoToCSR faild: %s", err) 276 return 277 } 278 } 279 csr, err = sw.CreateSm2CertificateRequestToMem(&tpl, key) 280 return 281 } 282 283 // 检查并获取签名算法 284 // 285 // Deprecated: 国密证书的签署改为使用`gitee.com/zhaochuninhefei/cfssl-gm` 286 func signerAlgo(priv crypto.Signer) x509.SignatureAlgorithm { 287 switch priv.Public().(type) { 288 case *sm2.PublicKey: 289 return x509.SM2WithSM3 290 default: 291 return x509.UnknownSignatureAlgorithm 292 } 293 } 294 295 // appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR 296 // 297 // Deprecated: 国密证书的签署改为使用`gitee.com/zhaochuninhefei/cfssl-gm` 298 func appendCAInfoToCSR(reqConf *csr.CAConfig, csreq *x509.CertificateRequest) error { 299 pathlen := reqConf.PathLength 300 if pathlen == 0 && !reqConf.PathLenZero { 301 pathlen = -1 302 } 303 val, err := asn1.Marshal(csr.BasicConstraints{IsCA: true, MaxPathLen: pathlen}) 304 305 if err != nil { 306 return err 307 } 308 csreq.ExtraExtensions = []pkix.Extension{ 309 { 310 Id: asn1.ObjectIdentifier{2, 5, 29, 19}, // BasicConstraints的OID 311 Value: val, 312 Critical: true, 313 }, 314 } 315 return nil 316 }