github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/crypto/expiration_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package crypto
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/pem"
    12  	"errors"
    13  	"fmt"
    14  	"io/ioutil"
    15  	"path/filepath"
    16  	"strings"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/golang/protobuf/proto"
    21  	"github.com/hechain20/hechain/common/crypto/tlsgen"
    22  	"github.com/hechain20/hechain/protoutil"
    23  	"github.com/hyperledger/fabric-protos-go/msp"
    24  	"github.com/stretchr/testify/require"
    25  )
    26  
    27  func TestX509CertExpiresAt(t *testing.T) {
    28  	certBytes, err := ioutil.ReadFile(filepath.Join("testdata", "cert.pem"))
    29  	require.NoError(t, err)
    30  	sId := &msp.SerializedIdentity{
    31  		IdBytes: certBytes,
    32  	}
    33  	serializedIdentity, err := proto.Marshal(sId)
    34  	require.NoError(t, err)
    35  	expirationTime := ExpiresAt(serializedIdentity)
    36  	require.Equal(t, time.Date(2027, 8, 17, 12, 19, 48, 0, time.UTC), expirationTime)
    37  }
    38  
    39  func TestX509InvalidCertExpiresAt(t *testing.T) {
    40  	certBytes, err := ioutil.ReadFile(filepath.Join("testdata", "badCert.pem"))
    41  	require.NoError(t, err)
    42  	sId := &msp.SerializedIdentity{
    43  		IdBytes: certBytes,
    44  	}
    45  	serializedIdentity, err := proto.Marshal(sId)
    46  	require.NoError(t, err)
    47  	expirationTime := ExpiresAt(serializedIdentity)
    48  	require.True(t, expirationTime.IsZero())
    49  }
    50  
    51  func TestIdemixIdentityExpiresAt(t *testing.T) {
    52  	idemixId := &msp.SerializedIdemixIdentity{
    53  		NymX: []byte{1, 2, 3},
    54  		NymY: []byte{1, 2, 3},
    55  		Ou:   []byte("OU1"),
    56  	}
    57  	idemixBytes, err := proto.Marshal(idemixId)
    58  	require.NoError(t, err)
    59  	sId := &msp.SerializedIdentity{
    60  		IdBytes: idemixBytes,
    61  	}
    62  	serializedIdentity, err := proto.Marshal(sId)
    63  	require.NoError(t, err)
    64  	expirationTime := ExpiresAt(serializedIdentity)
    65  	require.True(t, expirationTime.IsZero())
    66  }
    67  
    68  func TestInvalidIdentityExpiresAt(t *testing.T) {
    69  	expirationTime := ExpiresAt([]byte{1, 2, 3})
    70  	require.True(t, expirationTime.IsZero())
    71  }
    72  
    73  func TestTrackExpiration(t *testing.T) {
    74  	ca, err := tlsgen.NewCA()
    75  	require.NoError(t, err)
    76  
    77  	now := time.Now()
    78  	expirationTime := certExpirationTime(ca.CertBytes())
    79  
    80  	timeUntilExpiration := expirationTime.Sub(now)
    81  	timeUntilOneMonthBeforeExpiration := timeUntilExpiration - 28*24*time.Hour
    82  	timeUntil2DaysBeforeExpiration := timeUntilExpiration - 2*24*time.Hour - time.Hour*12
    83  
    84  	monthBeforeExpiration := now.Add(timeUntilOneMonthBeforeExpiration)
    85  	twoDaysBeforeExpiration := now.Add(timeUntil2DaysBeforeExpiration)
    86  
    87  	tlsCert, err := ca.NewServerCertKeyPair("127.0.0.1")
    88  	require.NoError(t, err)
    89  
    90  	signingIdentity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
    91  		IdBytes: tlsCert.Cert,
    92  	})
    93  
    94  	warnShouldNotBeInvoked := func(format string, args ...interface{}) {
    95  		t.Fatalf(format, args...)
    96  	}
    97  
    98  	var formattedWarning string
    99  	warnShouldBeInvoked := func(format string, args ...interface{}) {
   100  		formattedWarning = fmt.Sprintf(format, args...)
   101  	}
   102  
   103  	var formattedInfo string
   104  	infoShouldBeInvoked := func(format string, args ...interface{}) {
   105  		formattedInfo = fmt.Sprintf(format, args...)
   106  	}
   107  
   108  	for _, testCase := range []struct {
   109  		description        string
   110  		tls                bool
   111  		serverCert         []byte
   112  		clientCertChain    [][]byte
   113  		sIDBytes           []byte
   114  		info               MessageFunc
   115  		warn               MessageFunc
   116  		now                time.Time
   117  		expectedInfoPrefix string
   118  		expectedWarn       string
   119  	}{
   120  		{
   121  			description: "No TLS, enrollment cert isn't valid logs a warning",
   122  			warn:        warnShouldNotBeInvoked,
   123  			sIDBytes:    []byte{1, 2, 3},
   124  		},
   125  		{
   126  			description:        "No TLS, enrollment cert expires soon",
   127  			sIDBytes:           signingIdentity,
   128  			info:               infoShouldBeInvoked,
   129  			warn:               warnShouldBeInvoked,
   130  			now:                monthBeforeExpiration,
   131  			expectedInfoPrefix: "The enrollment certificate will expire on",
   132  			expectedWarn:       "The enrollment certificate will expire within one week",
   133  		},
   134  		{
   135  			description:        "TLS, server cert expires soon",
   136  			info:               infoShouldBeInvoked,
   137  			warn:               warnShouldBeInvoked,
   138  			now:                monthBeforeExpiration,
   139  			tls:                true,
   140  			serverCert:         tlsCert.Cert,
   141  			expectedInfoPrefix: "The server TLS certificate will expire on",
   142  			expectedWarn:       "The server TLS certificate will expire within one week",
   143  		},
   144  		{
   145  			description:        "TLS, server cert expires really soon",
   146  			info:               infoShouldBeInvoked,
   147  			warn:               warnShouldBeInvoked,
   148  			now:                twoDaysBeforeExpiration,
   149  			tls:                true,
   150  			serverCert:         tlsCert.Cert,
   151  			expectedInfoPrefix: "The server TLS certificate will expire on",
   152  			expectedWarn:       "The server TLS certificate expires within 2 days and 12 hours",
   153  		},
   154  		{
   155  			description:  "TLS, server cert has expired",
   156  			info:         infoShouldBeInvoked,
   157  			warn:         warnShouldBeInvoked,
   158  			now:          expirationTime.Add(time.Hour),
   159  			tls:          true,
   160  			serverCert:   tlsCert.Cert,
   161  			expectedWarn: "The server TLS certificate has expired",
   162  		},
   163  		{
   164  			description:        "TLS, client cert expires soon",
   165  			info:               infoShouldBeInvoked,
   166  			warn:               warnShouldBeInvoked,
   167  			now:                monthBeforeExpiration,
   168  			tls:                true,
   169  			clientCertChain:    [][]byte{tlsCert.Cert},
   170  			expectedInfoPrefix: "The client TLS certificate will expire on",
   171  			expectedWarn:       "The client TLS certificate will expire within one week",
   172  		},
   173  	} {
   174  		t.Run(testCase.description, func(t *testing.T) {
   175  			defer func() {
   176  				formattedWarning = ""
   177  				formattedInfo = ""
   178  			}()
   179  
   180  			fakeTimeAfter := func(duration time.Duration, f func()) *time.Timer {
   181  				require.NotEmpty(t, testCase.expectedWarn)
   182  				threeWeeks := 3 * 7 * 24 * time.Hour
   183  				require.Equal(t, threeWeeks, duration)
   184  				f()
   185  				return nil
   186  			}
   187  
   188  			TrackExpiration(testCase.tls,
   189  				testCase.serverCert,
   190  				testCase.clientCertChain,
   191  				testCase.sIDBytes,
   192  				testCase.info,
   193  				testCase.warn,
   194  				testCase.now,
   195  				fakeTimeAfter)
   196  
   197  			if testCase.expectedInfoPrefix != "" {
   198  				require.True(t, strings.HasPrefix(formattedInfo, testCase.expectedInfoPrefix))
   199  			} else {
   200  				require.Empty(t, formattedInfo)
   201  			}
   202  
   203  			if testCase.expectedWarn != "" {
   204  				require.Equal(t, testCase.expectedWarn, formattedWarning)
   205  			} else {
   206  				require.Empty(t, formattedWarning)
   207  			}
   208  		})
   209  	}
   210  }
   211  
   212  func TestLogNonPubKeyMismatchErr(t *testing.T) {
   213  	ca, err := tlsgen.NewCA()
   214  	require.NoError(t, err)
   215  
   216  	aliceKeyPair, err := ca.NewClientCertKeyPair()
   217  	require.NoError(t, err)
   218  
   219  	bobKeyPair, err := ca.NewClientCertKeyPair()
   220  	require.NoError(t, err)
   221  
   222  	expected := &bytes.Buffer{}
   223  	expected.WriteString(fmt.Sprintf("Failed determining if public key of %s matches public key of %s: foo",
   224  		string(aliceKeyPair.Cert),
   225  		string(bobKeyPair.Cert)))
   226  
   227  	b := &bytes.Buffer{}
   228  	f := func(template string, args ...interface{}) {
   229  		fmt.Fprintf(b, template, args...)
   230  	}
   231  
   232  	LogNonPubKeyMismatchErr(f, errors.New("foo"), aliceKeyPair.TLSCert.Raw, bobKeyPair.TLSCert.Raw)
   233  
   234  	require.Equal(t, expected.String(), b.String())
   235  }
   236  
   237  func TestCertificatesWithSamePublicKey(t *testing.T) {
   238  	ca, err := tlsgen.NewCA()
   239  	require.NoError(t, err)
   240  
   241  	bobKeyPair, err := ca.NewClientCertKeyPair()
   242  	require.NoError(t, err)
   243  
   244  	bobCert := bobKeyPair.Cert
   245  	bob := pem2der(bobCert)
   246  
   247  	aliceCert := `-----BEGIN CERTIFICATE-----
   248  MIIBNjCB3KADAgECAgELMAoGCCqGSM49BAMCMBAxDjAMBgNVBAUTBUFsaWNlMB4X
   249  DTIwMDgxODIxMzU1NFoXDTIwMDgyMDIxMzU1NFowEDEOMAwGA1UEBRMFQWxpY2Uw
   250  WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQjZP5VD/RaczoPFbA4gkt1qb54R6SP
   251  J/V5oxkhDboG9xWi0wpyghaMGwwxC7Q9wegEnyOVp9nXoLrQ8LUJ5BfZoycwJTAO
   252  BgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCgYIKoZIzj0EAwID
   253  SQAwRgIhAK4le5XgH5edyhaQ9Sz7sFz3Zc4bbhPAzt9zQUYnoqK+AiEA5zcyLB/4
   254  Oqe93lroE6GF9W7UoCZFzD7lXsWku/dgFOU=
   255  -----END CERTIFICATE-----`
   256  
   257  	reIssuedAliceCert := `-----BEGIN CERTIFICATE-----
   258  MIIBNDCB3KADAgECAgELMAoGCCqGSM49BAMCMBAxDjAMBgNVBAUTBUFsaWNlMB4X
   259  DTIwMDgxODIxMzY1NFoXDTIwMDgyMDIxMzY1NFowEDEOMAwGA1UEBRMFQWxpY2Uw
   260  WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQjZP5VD/RaczoPFbA4gkt1qb54R6SP
   261  J/V5oxkhDboG9xWi0wpyghaMGwwxC7Q9wegEnyOVp9nXoLrQ8LUJ5BfZoycwJTAO
   262  BgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCgYIKoZIzj0EAwID
   263  RwAwRAIgDc8WyXFvsxCk97KS7D/LdYJxMpDKdHNFqpzJT9LddlsCIEr8KcMd/t5p
   264  cRv6rqxvy5M+t0DhRtiwCen70YCUsksb
   265  -----END CERTIFICATE-----`
   266  
   267  	alice := pem2der([]byte(aliceCert))
   268  	aliceMakesComeback := pem2der([]byte(reIssuedAliceCert))
   269  
   270  	for _, test := range []struct {
   271  		description string
   272  		errContains string
   273  		first       []byte
   274  		second      []byte
   275  	}{
   276  		{
   277  			description: "Bad first certificate",
   278  			errContains: "malformed certificate",
   279  			first:       []byte{1, 2, 3},
   280  			second:      bob,
   281  		},
   282  
   283  		{
   284  			description: "Bad second certificate",
   285  			errContains: "malformed certificate",
   286  			first:       alice,
   287  			second:      []byte{1, 2, 3},
   288  		},
   289  
   290  		{
   291  			description: "Different certificate",
   292  			errContains: ErrPubKeyMismatch.Error(),
   293  			first:       alice,
   294  			second:      bob,
   295  		},
   296  
   297  		{
   298  			description: "Same certificate",
   299  			first:       alice,
   300  			second:      alice,
   301  		},
   302  
   303  		{
   304  			description: "Same certificate but different validity period",
   305  			first:       alice,
   306  			second:      aliceMakesComeback,
   307  		},
   308  	} {
   309  		t.Run(test.description, func(t *testing.T) {
   310  			err := CertificatesWithSamePublicKey(test.first, test.second)
   311  			if test.errContains != "" {
   312  				require.Error(t, err)
   313  				require.Contains(t, err.Error(), test.errContains)
   314  				return
   315  			}
   316  
   317  			require.NoError(t, err)
   318  		})
   319  	}
   320  }
   321  
   322  func pem2der(p []byte) []byte {
   323  	b, _ := pem.Decode(p)
   324  	return b.Bytes
   325  }