github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/cryptogen/ca/ca_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  package ca_test
     7  
     8  import (
     9  	"crypto/ecdsa"
    10  	"crypto/x509"
    11  	"io/ioutil"
    12  	"net"
    13  	"os"
    14  	"path/filepath"
    15  	"testing"
    16  
    17  	"github.com/hechain20/hechain/internal/cryptogen/ca"
    18  	"github.com/hechain20/hechain/internal/cryptogen/csp"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  const (
    23  	testCAName             = "root0"
    24  	testCA2Name            = "root1"
    25  	testCA3Name            = "root2"
    26  	testName               = "cert0"
    27  	testName2              = "cert1"
    28  	testName3              = "cert2"
    29  	testIP                 = "172.16.10.31"
    30  	testCountry            = "US"
    31  	testProvince           = "California"
    32  	testLocality           = "San Francisco"
    33  	testOrganizationalUnit = "Hechain"
    34  	testStreetAddress      = "testStreetAddress"
    35  	testPostalCode         = "123456"
    36  )
    37  
    38  func TestLoadCertificateECDSA(t *testing.T) {
    39  	testDir, err := ioutil.TempDir("", "ca-test")
    40  	if err != nil {
    41  		t.Fatalf("Failed to create test directory: %s", err)
    42  	}
    43  	defer os.RemoveAll(testDir)
    44  
    45  	// generate private key
    46  	certDir, err := ioutil.TempDir(testDir, "certs")
    47  	if err != nil {
    48  		t.Fatalf("Failed to create certs directory: %s", err)
    49  	}
    50  	priv, err := csp.GeneratePrivateKey(certDir)
    51  	require.NoError(t, err, "Failed to generate signed certificate")
    52  
    53  	// create our CA
    54  	caDir := filepath.Join(testDir, "ca")
    55  	rootCA, err := ca.NewCA(
    56  		caDir,
    57  		testCA3Name,
    58  		testCA3Name,
    59  		testCountry,
    60  		testProvince,
    61  		testLocality,
    62  		testOrganizationalUnit,
    63  		testStreetAddress,
    64  		testPostalCode,
    65  	)
    66  	require.NoError(t, err, "Error generating CA")
    67  
    68  	cert, err := rootCA.SignCertificate(
    69  		certDir,
    70  		testName3,
    71  		nil,
    72  		nil,
    73  		&priv.PublicKey,
    74  		x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
    75  		[]x509.ExtKeyUsage{x509.ExtKeyUsageAny},
    76  	)
    77  	require.NoError(t, err, "Failed to generate signed certificate")
    78  	// KeyUsage should be x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
    79  	require.Equal(t, x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
    80  		cert.KeyUsage)
    81  	require.Contains(t, cert.ExtKeyUsage, x509.ExtKeyUsageAny)
    82  
    83  	loadedCert, err := ca.LoadCertificateECDSA(certDir)
    84  	require.NoError(t, err)
    85  	require.NotNil(t, loadedCert, "Should load cert")
    86  	require.Equal(t, cert.SerialNumber, loadedCert.SerialNumber, "Should have same serial number")
    87  	require.Equal(t, cert.Subject.CommonName, loadedCert.Subject.CommonName, "Should have same CN")
    88  }
    89  
    90  func TestLoadCertificateECDSA_wrongEncoding(t *testing.T) {
    91  	testDir, err := ioutil.TempDir("", "wrongEncoding")
    92  	require.NoError(t, err, "failed to create test directory")
    93  	defer os.RemoveAll(testDir)
    94  
    95  	filename := filepath.Join(testDir, "wrong_encoding.pem")
    96  	err = ioutil.WriteFile(filename, []byte("wrong_encoding"), 0o644) // Wrong encoded cert
    97  	require.NoErrorf(t, err, "failed to create file %s", filename)
    98  
    99  	_, err = ca.LoadCertificateECDSA(testDir)
   100  	require.NotNil(t, err)
   101  	require.EqualError(t, err, filename+": wrong PEM encoding")
   102  }
   103  
   104  func TestLoadCertificateECDSA_empty_DER_cert(t *testing.T) {
   105  	testDir, err := ioutil.TempDir("", "ca-test")
   106  	require.NoError(t, err, "failed to create test directory")
   107  	defer os.RemoveAll(testDir)
   108  
   109  	filename := filepath.Join(testDir, "empty.pem")
   110  	empty_cert := "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"
   111  	err = ioutil.WriteFile(filename, []byte(empty_cert), 0o644)
   112  	require.NoErrorf(t, err, "failed to create file %s", filename)
   113  
   114  	cert, err := ca.LoadCertificateECDSA(testDir)
   115  	require.Nil(t, cert)
   116  	require.NotNil(t, err)
   117  	require.EqualError(t, err, filename+": wrong DER encoding")
   118  }
   119  
   120  func TestNewCA(t *testing.T) {
   121  	testDir, err := ioutil.TempDir("", "ca-test")
   122  	if err != nil {
   123  		t.Fatalf("Failed to create test directory: %s", err)
   124  	}
   125  	defer os.RemoveAll(testDir)
   126  
   127  	caDir := filepath.Join(testDir, "ca")
   128  	rootCA, err := ca.NewCA(
   129  		caDir,
   130  		testCAName,
   131  		testCAName,
   132  		testCountry,
   133  		testProvince,
   134  		testLocality,
   135  		testOrganizationalUnit,
   136  		testStreetAddress,
   137  		testPostalCode,
   138  	)
   139  	require.NoError(t, err, "Error generating CA")
   140  	require.NotNil(t, rootCA, "Failed to return CA")
   141  	require.NotNil(t, rootCA.Signer,
   142  		"rootCA.Signer should not be empty")
   143  	require.IsType(t, &x509.Certificate{}, rootCA.SignCert,
   144  		"rootCA.SignCert should be type x509.Certificate")
   145  
   146  	// check to make sure the root public key was stored
   147  	pemFile := filepath.Join(caDir, testCAName+"-cert.pem")
   148  	require.Equal(t, true, checkForFile(pemFile),
   149  		"Expected to find file "+pemFile)
   150  
   151  	require.NotEmpty(t, rootCA.SignCert.Subject.Country, "country cannot be empty.")
   152  	require.Equal(t, testCountry, rootCA.SignCert.Subject.Country[0], "Failed to match country")
   153  	require.NotEmpty(t, rootCA.SignCert.Subject.Province, "province cannot be empty.")
   154  	require.Equal(t, testProvince, rootCA.SignCert.Subject.Province[0], "Failed to match province")
   155  	require.NotEmpty(t, rootCA.SignCert.Subject.Locality, "locality cannot be empty.")
   156  	require.Equal(t, testLocality, rootCA.SignCert.Subject.Locality[0], "Failed to match locality")
   157  	require.NotEmpty(t, rootCA.SignCert.Subject.OrganizationalUnit, "organizationalUnit cannot be empty.")
   158  	require.Equal(t, testOrganizationalUnit, rootCA.SignCert.Subject.OrganizationalUnit[0], "Failed to match organizationalUnit")
   159  	require.NotEmpty(t, rootCA.SignCert.Subject.StreetAddress, "streetAddress cannot be empty.")
   160  	require.Equal(t, testStreetAddress, rootCA.SignCert.Subject.StreetAddress[0], "Failed to match streetAddress")
   161  	require.NotEmpty(t, rootCA.SignCert.Subject.PostalCode, "postalCode cannot be empty.")
   162  	require.Equal(t, testPostalCode, rootCA.SignCert.Subject.PostalCode[0], "Failed to match postalCode")
   163  }
   164  
   165  func TestGenerateSignCertificate(t *testing.T) {
   166  	testDir, err := ioutil.TempDir("", "ca-test")
   167  	if err != nil {
   168  		t.Fatalf("Failed to create test directory: %s", err)
   169  	}
   170  	defer os.RemoveAll(testDir)
   171  
   172  	// generate private key
   173  	certDir, err := ioutil.TempDir(testDir, "certs")
   174  	if err != nil {
   175  		t.Fatalf("Failed to create certs directory: %s", err)
   176  	}
   177  	priv, err := csp.GeneratePrivateKey(certDir)
   178  	require.NoError(t, err, "Failed to generate signed certificate")
   179  
   180  	// create our CA
   181  	caDir := filepath.Join(testDir, "ca")
   182  	rootCA, err := ca.NewCA(
   183  		caDir,
   184  		testCA2Name,
   185  		testCA2Name,
   186  		testCountry,
   187  		testProvince,
   188  		testLocality,
   189  		testOrganizationalUnit,
   190  		testStreetAddress,
   191  		testPostalCode,
   192  	)
   193  	require.NoError(t, err, "Error generating CA")
   194  
   195  	cert, err := rootCA.SignCertificate(
   196  		certDir,
   197  		testName,
   198  		nil,
   199  		nil,
   200  		&priv.PublicKey,
   201  		x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
   202  		[]x509.ExtKeyUsage{x509.ExtKeyUsageAny},
   203  	)
   204  	require.NoError(t, err, "Failed to generate signed certificate")
   205  	// KeyUsage should be x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
   206  	require.Equal(t, x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
   207  		cert.KeyUsage)
   208  	require.Contains(t, cert.ExtKeyUsage, x509.ExtKeyUsageAny)
   209  
   210  	cert, err = rootCA.SignCertificate(
   211  		certDir,
   212  		testName,
   213  		nil,
   214  		nil,
   215  		&priv.PublicKey,
   216  		x509.KeyUsageDigitalSignature,
   217  		[]x509.ExtKeyUsage{},
   218  	)
   219  	require.NoError(t, err, "Failed to generate signed certificate")
   220  	require.Equal(t, 0, len(cert.ExtKeyUsage))
   221  
   222  	// make sure ous are correctly set
   223  	ous := []string{"TestOU", "PeerOU"}
   224  	cert, err = rootCA.SignCertificate(certDir, testName, ous, nil, &priv.PublicKey,
   225  		x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
   226  	require.NoError(t, err)
   227  	require.Contains(t, cert.Subject.OrganizationalUnit, ous[0])
   228  	require.Contains(t, cert.Subject.OrganizationalUnit, ous[1])
   229  
   230  	// make sure sans are correctly set
   231  	sans := []string{testName2, testName3, testIP}
   232  	cert, err = rootCA.SignCertificate(certDir, testName, nil, sans, &priv.PublicKey,
   233  		x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
   234  	require.NoError(t, err)
   235  	require.Contains(t, cert.DNSNames, testName2)
   236  	require.Contains(t, cert.DNSNames, testName3)
   237  	require.Contains(t, cert.IPAddresses, net.ParseIP(testIP).To4())
   238  	require.Equal(t, len(cert.DNSNames), 2)
   239  
   240  	// check to make sure the signed public key was stored
   241  	pemFile := filepath.Join(certDir, testName+"-cert.pem")
   242  	require.Equal(t, true, checkForFile(pemFile),
   243  		"Expected to find file "+pemFile)
   244  
   245  	_, err = rootCA.SignCertificate(certDir, "empty/CA", nil, nil, &priv.PublicKey,
   246  		x509.KeyUsageKeyEncipherment, []x509.ExtKeyUsage{x509.ExtKeyUsageAny})
   247  	require.Error(t, err, "Bad name should fail")
   248  
   249  	// use an empty CA to test error path
   250  	badCA := &ca.CA{
   251  		Name:     "badCA",
   252  		SignCert: &x509.Certificate{},
   253  	}
   254  	_, err = badCA.SignCertificate(certDir, testName, nil, nil, &ecdsa.PublicKey{},
   255  		x509.KeyUsageKeyEncipherment, []x509.ExtKeyUsage{x509.ExtKeyUsageAny})
   256  	require.Error(t, err, "Empty CA should not be able to sign")
   257  }
   258  
   259  func checkForFile(file string) bool {
   260  	if _, err := os.Stat(file); os.IsNotExist(err) {
   261  		return false
   262  	}
   263  	return true
   264  }