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 }