gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/x509test/x509_test.go (about) 1 package x509test 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/elliptic" 6 "crypto/rand" 7 "crypto/x509/pkix" 8 "encoding/asn1" 9 "fmt" 10 "gitee.com/ks-custle/core-gm/sm2" 11 "gitee.com/ks-custle/core-gm/utils" 12 "gitee.com/ks-custle/core-gm/x509" 13 "io/ioutil" 14 "net" 15 "net/url" 16 "os" 17 "path" 18 "strings" 19 "testing" 20 "time" 21 ) 22 23 func TestClearTestdata(t *testing.T) { 24 dir, _ := ioutil.ReadDir("testdata") 25 for _, f := range dir { 26 err := os.Remove(path.Join("testdata", f.Name())) 27 if err != nil { 28 t.Fatal(err) 29 } 30 } 31 } 32 33 func TestCreateCertFromCA_sm2(t *testing.T) { 34 certTypePre := "sm2_" 35 36 certType := certTypePre + "ca" 37 caPriv, caCert, err := createCACert(certType) 38 if err != nil { 39 t.Fatal(err) 40 } 41 fmt.Printf("生成CA密钥对与CA证书成功 %s\n", certType) 42 43 certType = certTypePre + "intermediateCA" 44 intermediateCaPriv, intermediateCaCert, err := createIntermediateCACert(certType, caPriv, caCert) 45 if err != nil { 46 t.Fatal(err) 47 } 48 fmt.Printf("生成IntermediateCA密钥对与IntermediateCA证书成功 %s\n", certType) 49 50 certType = certTypePre + "sign" 51 err = createSignCert(intermediateCaPriv, intermediateCaCert, certType) 52 if err != nil { 53 t.Fatal(err) 54 } 55 fmt.Printf("生成 %s 密钥对并模拟CA为其颁发证书成功\n", certType) 56 57 certType = certTypePre + "enc" 58 err = createEncCert(intermediateCaPriv, intermediateCaCert, certType) 59 if err != nil { 60 t.Fatal(err) 61 } 62 fmt.Printf("生成 %s 密钥对并模拟CA为其颁发证书成功\n", certType) 63 64 certType = certTypePre + "auth" 65 err = createAuthCert(intermediateCaPriv, intermediateCaCert, certType) 66 if err != nil { 67 t.Fatal(err) 68 } 69 fmt.Printf("生成 %s 密钥对并模拟CA为其颁发证书成功\n", certType) 70 } 71 72 func TestCreateCertFromCA_ecdsa(t *testing.T) { 73 certTypePre := "ecdsa_" 74 certType := certTypePre + "ca" 75 caPriv, caCert, err := createCACert(certType) 76 if err != nil { 77 t.Fatal(err) 78 } 79 fmt.Printf("生成CA密钥对与CA证书成功 %s\n", certType) 80 81 certType = certTypePre + "intermediateCA" 82 intermediateCaPriv, intermediateCaCert, err := createIntermediateCACert(certType, caPriv, caCert) 83 if err != nil { 84 t.Fatal(err) 85 } 86 fmt.Printf("生成IntermediateCA密钥对与IntermediateCA证书成功 %s\n", certType) 87 88 certType = certTypePre + "sign" 89 err = createSignCert(intermediateCaPriv, intermediateCaCert, certType) 90 if err != nil { 91 t.Fatal(err) 92 } 93 fmt.Printf("生成 %s 密钥对并模拟CA为其颁发证书成功\n", certType) 94 95 certType = certTypePre + "enc" 96 err = createEncCert(intermediateCaPriv, intermediateCaCert, certType) 97 if err != nil { 98 t.Fatal(err) 99 } 100 fmt.Printf("生成 %s 密钥对并模拟CA为其颁发证书成功\n", certType) 101 102 certType = certTypePre + "auth" 103 err = createAuthCert(intermediateCaPriv, intermediateCaCert, certType) 104 if err != nil { 105 t.Fatal(err) 106 } 107 fmt.Printf("生成 %s 密钥对并模拟CA为其颁发证书成功\n", certType) 108 } 109 110 func createCACert(certType string) (interface{}, *x509.Certificate, error) { 111 // 生成密钥对 112 privKey, pubKey, err := createKeys(certType) 113 if err != nil { 114 return nil, nil, err 115 } 116 userKeyUsage := x509.KeyUsageCertSign + x509.KeyUsageCRLSign 117 //goland:noinspection GoPreferNilSlice 118 userExtKeyUsage := []x509.ExtKeyUsage{ 119 // ExtKeyUsageAny, 120 // ExtKeyUsageServerAuth, 121 // ExtKeyUsageClientAuth, 122 // ExtKeyUsageCodeSigning, 123 // ExtKeyUsageEmailProtection, 124 // ExtKeyUsageIPSECEndSystem, 125 // ExtKeyUsageIPSECTunnel, 126 // ExtKeyUsageIPSECUser, 127 // ExtKeyUsageTimeStamping, 128 // ExtKeyUsageOCSPSigning, 129 // ExtKeyUsageMicrosoftServerGatedCrypto, 130 // ExtKeyUsageNetscapeServerGatedCrypto, 131 } 132 // 创建证书,ca证书自签名 133 cert, err := createCertSignSelf("ca.test.com", "test", "ca", "CN", "Anhui Hefei", true, true, userKeyUsage, userExtKeyUsage, nil, certType, pubKey, privKey) 134 if err != nil { 135 return nil, nil, err 136 } 137 // 检查证书签名,因为是ca证书自签名,所以使用本证书自验 138 err = cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature) 139 if err != nil { 140 return nil, nil, err 141 } else { 142 fmt.Printf("CheckSignature ok\n") 143 } 144 return privKey, cert, nil 145 } 146 147 func createIntermediateCACert(certType string, caPriv interface{}, caCert *x509.Certificate) (interface{}, *x509.Certificate, error) { 148 // 生成密钥对 149 privKey, pubKey, err := createKeys(certType) 150 if err != nil { 151 return nil, nil, err 152 } 153 userKeyUsage := x509.KeyUsageCertSign + x509.KeyUsageCRLSign 154 //goland:noinspection GoPreferNilSlice 155 userExtKeyUsage := []x509.ExtKeyUsage{ 156 // ExtKeyUsageAny, 157 // ExtKeyUsageServerAuth, 158 // ExtKeyUsageClientAuth, 159 // ExtKeyUsageCodeSigning, 160 // ExtKeyUsageEmailProtection, 161 // ExtKeyUsageIPSECEndSystem, 162 // ExtKeyUsageIPSECTunnel, 163 // ExtKeyUsageIPSECUser, 164 // ExtKeyUsageTimeStamping, 165 // ExtKeyUsageOCSPSigning, 166 // ExtKeyUsageMicrosoftServerGatedCrypto, 167 // ExtKeyUsageNetscapeServerGatedCrypto, 168 } 169 // 创建证书,ca证书自签名 170 cert, err := createCertSignParent("intermediateCa.test.com", "test", "intermediateCa", "CN", "Anhui Hefei", true, true, userKeyUsage, userExtKeyUsage, nil, certType, pubKey, caPriv, caCert) 171 if err != nil { 172 return nil, nil, err 173 } 174 // 使用父证书caCert验签 175 err = caCert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature) 176 if err != nil { 177 return nil, nil, err 178 } else { 179 fmt.Printf("CheckSignature ok\n") 180 } 181 return privKey, cert, nil 182 } 183 184 func createSignCert(caPriv interface{}, caCert *x509.Certificate, certType string) error { 185 // 生成sm2密钥对 186 _, pubKey, err := createKeys(certType) 187 if err != nil { 188 return err 189 } 190 userKeyUsage := x509.KeyUsageDigitalSignature + x509.KeyUsageContentCommitment 191 userExtKeyUsage := []x509.ExtKeyUsage{ 192 // ExtKeyUsageAny, 193 x509.ExtKeyUsageServerAuth, 194 x509.ExtKeyUsageClientAuth, 195 // ExtKeyUsageCodeSigning, 196 // ExtKeyUsageEmailProtection, 197 // ExtKeyUsageIPSECEndSystem, 198 // ExtKeyUsageIPSECTunnel, 199 // ExtKeyUsageIPSECUser, 200 // ExtKeyUsageTimeStamping, 201 // ExtKeyUsageOCSPSigning, 202 // ExtKeyUsageMicrosoftServerGatedCrypto, 203 // ExtKeyUsageNetscapeServerGatedCrypto, 204 } 205 // 模拟CA颁发证书,注意此时ca证书是父证书 206 cert, err := createCertSignParent("server.test.com", "test", "server", "CN", "Anhui Hefei", false, false, userKeyUsage, userExtKeyUsage, nil, certType, pubKey, caPriv, caCert) 207 if err != nil { 208 return err 209 } 210 // 使用父证书caCert验签 211 err = caCert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature) 212 if err != nil { 213 return err 214 } else { 215 fmt.Printf("CheckSignature ok\n") 216 } 217 return nil 218 } 219 220 func createEncCert(caPriv interface{}, caCert *x509.Certificate, certType string) error { 221 // 生成密钥对 222 _, pubKey, err := createKeys(certType) 223 if err != nil { 224 return err 225 } 226 userKeyUsage := x509.KeyUsageKeyEncipherment + x509.KeyUsageDataEncipherment 227 //goland:noinspection GoPreferNilSlice 228 userExtKeyUsage := []x509.ExtKeyUsage{ 229 // ExtKeyUsageAny, 230 // ExtKeyUsageServerAuth, 231 // ExtKeyUsageClientAuth, 232 // ExtKeyUsageCodeSigning, 233 // ExtKeyUsageEmailProtection, 234 // ExtKeyUsageIPSECEndSystem, 235 // ExtKeyUsageIPSECTunnel, 236 // ExtKeyUsageIPSECUser, 237 // ExtKeyUsageTimeStamping, 238 // ExtKeyUsageOCSPSigning, 239 // ExtKeyUsageMicrosoftServerGatedCrypto, 240 // ExtKeyUsageNetscapeServerGatedCrypto, 241 } 242 // 模拟CA颁发证书,注意此时ca证书是父证书 243 cert, err := createCertSignParent("server.test.com", "test", "server", "CN", "Anhui Hefei", false, false, userKeyUsage, userExtKeyUsage, nil, certType, pubKey, caPriv, caCert) 244 if err != nil { 245 return err 246 } 247 // 使用父证书caCert验签 248 err = caCert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature) 249 if err != nil { 250 return err 251 } else { 252 fmt.Printf("CheckSignature ok\n") 253 } 254 return nil 255 } 256 257 func createAuthCert(caPriv interface{}, caCert *x509.Certificate, certType string) error { 258 // 生成密钥对 259 _, pubKey, err := createKeys(certType) 260 if err != nil { 261 return err 262 } 263 userKeyUsage := x509.KeyUsageDigitalSignature + x509.KeyUsageContentCommitment 264 userExtKeyUsage := []x509.ExtKeyUsage{ 265 // ExtKeyUsageAny, 266 x509.ExtKeyUsageServerAuth, 267 x509.ExtKeyUsageClientAuth, 268 // ExtKeyUsageCodeSigning, 269 // ExtKeyUsageEmailProtection, 270 // ExtKeyUsageIPSECEndSystem, 271 // ExtKeyUsageIPSECTunnel, 272 // ExtKeyUsageIPSECUser, 273 // ExtKeyUsageTimeStamping, 274 // ExtKeyUsageOCSPSigning, 275 // ExtKeyUsageMicrosoftServerGatedCrypto, 276 // ExtKeyUsageNetscapeServerGatedCrypto, 277 } 278 // 模拟CA颁发证书,注意此时ca证书是父证书 279 cert, err := createCertSignParent("client.test.com", "test", "client", "CN", "Anhui Hefei", false, false, userKeyUsage, userExtKeyUsage, nil, certType, pubKey, caPriv, caCert) 280 if err != nil { 281 return err 282 } 283 // 使用父证书caCert验签 284 err = caCert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature) 285 if err != nil { 286 return err 287 } else { 288 fmt.Printf("CheckSignature ok\n") 289 } 290 return nil 291 } 292 293 func createKeys(certType string) (interface{}, interface{}, error) { 294 var priv, pub interface{} 295 var err error 296 297 if strings.HasPrefix(certType, "sm2_") { 298 // 生成sm2密钥对 299 priv, err = sm2.GenerateKey(rand.Reader) 300 if err != nil { 301 return nil, nil, err 302 } 303 pub = &priv.(*sm2.PrivateKey).PublicKey 304 } else if strings.HasPrefix(certType, "ecdsa_") { 305 // 生成ecdsa密钥对 306 priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 307 if err != nil { 308 return nil, nil, err 309 } 310 pub = &priv.(*ecdsa.PrivateKey).PublicKey 311 } 312 // 生成私钥pem文件 313 _, err = x509.WritePrivateKeytoPemFile("testdata/"+certType+"_key.pem", priv, nil) 314 if err != nil { 315 return nil, nil, err 316 } 317 // 生成公钥pem文件 318 _, err = x509.WritePublicKeytoPemFile("testdata/"+certType+"_pubkey.pem", pub) 319 if err != nil { 320 return nil, nil, err 321 } 322 // 从pem文件读取私钥 323 privKey, err := x509.ReadPrivateKeyFromPemFile("testdata/"+certType+"_key.pem", nil) 324 if err != nil { 325 return nil, nil, err 326 } 327 // 从pem文件读取公钥 328 pubKey, err := x509.ReadPublicKeyFromPemFile("testdata/" + certType + "_pubkey.pem") 329 if err != nil { 330 return nil, nil, err 331 } 332 return privKey, pubKey, nil 333 } 334 335 func createCertSignSelf(cn string, o string, ou string, c string, st string, bcs bool, isca bool, 336 ku x509.KeyUsage, ekus []x509.ExtKeyUsage, uekus []asn1.ObjectIdentifier, 337 certType string, pubKey interface{}, privKey interface{}) (*x509.Certificate, error) { 338 // 获取ski 339 var ski []byte 340 switch pk := pubKey.(type) { 341 case *sm2.PublicKey: 342 ski = x509.CreateEllipticSKI(pk.Curve, pk.X, pk.Y) 343 case *ecdsa.PublicKey: 344 ski = x509.CreateEllipticSKI(pk.Curve, pk.X, pk.Y) 345 default: 346 panic("不支持的公钥类型") 347 } 348 // 定义证书模板 349 template := createTemplate(cn, o, ou, c, st, bcs, isca, ski, ku, ekus, uekus, privKey) 350 // 创建自签名证书pem文件 351 _, err := x509.CreateCertificateToPemFile("testdata/"+certType+"_cert.cer", template, template, pubKey, privKey) 352 if err != nil { 353 return nil, err 354 } 355 // 可以使用命令`openssl x509 -noout -text -in testdata/user_cert.cer`查看生成的x509证书 356 // 读取证书pem文件 357 cert, err := x509.ReadCertificateFromPemFile("testdata/" + certType + "_cert.cer") 358 if err != nil { 359 return nil, err 360 } 361 return cert, nil 362 } 363 364 func createCertSignParent(cn string, o string, ou string, c string, st string, bcs bool, isca bool, 365 ku x509.KeyUsage, ekus []x509.ExtKeyUsage, uekus []asn1.ObjectIdentifier, 366 certType string, pubKey interface{}, privKey interface{}, parent *x509.Certificate) (*x509.Certificate, error) { 367 368 // 获取ski 369 var ski []byte 370 switch pk := pubKey.(type) { 371 case *sm2.PublicKey: 372 ski = x509.CreateEllipticSKI(pk.Curve, pk.X, pk.Y) 373 case *ecdsa.PublicKey: 374 ski = x509.CreateEllipticSKI(pk.Curve, pk.X, pk.Y) 375 default: 376 panic("不支持的公钥类型") 377 } 378 // 定义证书模板 379 template := createTemplate(cn, o, ou, c, st, bcs, isca, ski, ku, ekus, uekus, privKey) 380 // 创建自签名证书pem文件 381 _, err := x509.CreateCertificateToPemFile("testdata/"+certType+"_cert.cer", template, parent, pubKey, privKey) 382 if err != nil { 383 return nil, err 384 } 385 // 可以使用命令`openssl x509 -noout -text -in testdata/user_cert.cer`查看生成的x509证书 386 // 读取证书pem文件 387 cert, err := x509.ReadCertificateFromPemFile("testdata/" + certType + "_cert.cer") 388 if err != nil { 389 return nil, err 390 } 391 return cert, nil 392 } 393 394 func createTemplate(cn string, o string, ou string, c string, st string, bcs bool, isca bool, sId []byte, ku x509.KeyUsage, ekus []x509.ExtKeyUsage, uekus []asn1.ObjectIdentifier, privKey interface{}) *x509.Certificate { 395 var signAlg x509.SignatureAlgorithm 396 switch privKey.(type) { 397 case *sm2.PrivateKey: 398 signAlg = x509.SM2WithSM3 399 case *ecdsa.PrivateKey: 400 signAlg = x509.ECDSAWithSHA256 401 default: 402 panic("不支持的私钥类型") 403 } 404 405 // 定义证书模板 406 template := &x509.Certificate{ 407 // 证书序列号 408 SerialNumber: utils.GetRandBigInt(), 409 // 证书拥有者 410 Subject: pkix.Name{ 411 // CN 证书拥有者通用名, 一般是域名 412 CommonName: cn, 413 // O 证书拥有者组织机构 414 Organization: []string{o}, 415 // OU 证书拥有者组织单位, 隶属于Organization 416 OrganizationalUnit: []string{ou}, 417 // C 证书拥有者所在国家 418 Country: []string{"China"}, 419 // 附加名称 420 ExtraNames: []pkix.AttributeTypeAndValue{ 421 // This should override the Country, above. 422 { 423 // C 会覆盖Country 424 Type: []int{2, 5, 4, 6}, 425 Value: c, 426 }, 427 { 428 // ST 省市 429 Type: []int{2, 5, 4, 8}, 430 Value: st, 431 }, 432 }, 433 }, 434 // 证书有效期 十年 435 // NotBefore: time.Now(), 436 // NotAfter: time.Date(2032, time.December, 31, 23, 59, 59, 1, time.UTC), 437 NotBefore: time.Now().Add(-1 * time.Hour), 438 NotAfter: time.Now().Add(87600 * time.Hour), 439 // 证书签名算法 440 SignatureAlgorithm: signAlg, 441 BasicConstraintsValid: bcs, 442 IsCA: isca, 443 SubjectKeyId: sId, 444 // AuthorityKeyId: aId, 445 KeyUsage: ku, 446 ExtKeyUsage: ekus, 447 UnknownExtKeyUsage: uekus, 448 // x509 v3 版本不再使用 CommonName 而是使用这里的SAN扩展信息 449 DNSNames: []string{cn, "test.example.com"}, 450 EmailAddresses: []string{"test@example.com"}, 451 IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")}, 452 URIs: []*url.URL{parseURI("https://example.com/test#test")}, 453 } 454 return template 455 } 456 457 func parseURI(s string) *url.URL { 458 uri, err := url.Parse(s) 459 if err != nil { 460 panic(err) 461 } 462 return uri 463 }