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  }