Skip to content

Commit 7ca901e

Browse files
committed
[FAB-4138] Disable time-related cert expiration
This is a workaround for FAB-3678. Essentially, certificates do not expire. They can still be recovered using the appropriate mechanisms. Tests have been added to ensure that certificates whose time validity is in the past and in the future wrt the current local time are validated anyway. Change-Id: I87603177814af7b0d06d8acd232264d2977bbebc Signed-off-by: Angelo De Caro <[email protected]>
1 parent 27f996e commit 7ca901e

File tree

2 files changed

+107
-56
lines changed

2 files changed

+107
-56
lines changed

msp/cert_test.go

+89-55
Original file line numberDiff line numberDiff line change
@@ -67,63 +67,10 @@ func TestSanitizeCertInvalidInput(t *testing.T) {
6767
}
6868

6969
func TestSanitizeCert(t *testing.T) {
70-
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
71-
assert.NoError(t, err)
72-
70+
var k *ecdsa.PrivateKey
7371
var cert *x509.Certificate
7472
for {
75-
// Generate a self-signed certificate
76-
testExtKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
77-
testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{2, 59, 1}}
78-
extraExtensionData := []byte("extra extension")
79-
commonName := "test.example.com"
80-
template := x509.Certificate{
81-
SerialNumber: big.NewInt(1),
82-
Subject: pkix.Name{
83-
CommonName: commonName,
84-
Organization: []string{"Σ Acme Co"},
85-
Country: []string{"US"},
86-
ExtraNames: []pkix.AttributeTypeAndValue{
87-
{
88-
Type: []int{2, 5, 4, 42},
89-
Value: "Gopher",
90-
},
91-
// This should override the Country, above.
92-
{
93-
Type: []int{2, 5, 4, 6},
94-
Value: "NL",
95-
},
96-
},
97-
},
98-
NotBefore: time.Now().Add(-1 * time.Hour),
99-
NotAfter: time.Now().Add(1 * time.Hour),
100-
SignatureAlgorithm: x509.ECDSAWithSHA256,
101-
SubjectKeyId: []byte{1, 2, 3, 4},
102-
KeyUsage: x509.KeyUsageCertSign,
103-
ExtKeyUsage: testExtKeyUsage,
104-
UnknownExtKeyUsage: testUnknownExtKeyUsage,
105-
BasicConstraintsValid: true,
106-
IsCA: true,
107-
OCSPServer: []string{"http://ocurrentBCCSP.example.com"},
108-
IssuingCertificateURL: []string{"http://crt.example.com/ca1.crt"},
109-
DNSNames: []string{"test.example.com"},
110-
EmailAddresses: []string{"[email protected]"},
111-
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
112-
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
113-
PermittedDNSDomains: []string{".example.com", "example.com"},
114-
CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
115-
ExtraExtensions: []pkix.Extension{
116-
{
117-
Id: []int{1, 2, 3, 4},
118-
Value: extraExtensionData,
119-
},
120-
},
121-
}
122-
certRaw, err := x509.CreateCertificate(rand.Reader, &template, &template, &k.PublicKey, k)
123-
assert.NoError(t, err)
124-
125-
cert, err = x509.ParseCertificate(certRaw)
126-
assert.NoError(t, err)
73+
k, cert = generateSelfSignedCert(t, time.Now())
12774

12875
_, s, err := sw.UnmarshalECDSASignature(cert.Signature)
12976
assert.NoError(t, err)
@@ -147,3 +94,90 @@ func TestSanitizeCert(t *testing.T) {
14794
assert.NoError(t, err)
14895
assert.True(t, lowS)
14996
}
97+
98+
func TestCertExpiration(t *testing.T) {
99+
msp := &bccspmsp{}
100+
msp.opts = &x509.VerifyOptions{}
101+
msp.opts.DNSName = "test.example.com"
102+
103+
// Certificate is in the future
104+
_, cert := generateSelfSignedCert(t, time.Now().Add(24*time.Hour))
105+
msp.opts.Roots = x509.NewCertPool()
106+
msp.opts.Roots.AddCert(cert)
107+
_, err := msp.getUniqueValidationChain(cert)
108+
assert.NoError(t, err)
109+
110+
// Certificate is in the past
111+
_, cert = generateSelfSignedCert(t, time.Now().Add(-24*time.Hour))
112+
msp.opts.Roots = x509.NewCertPool()
113+
msp.opts.Roots.AddCert(cert)
114+
_, err = msp.getUniqueValidationChain(cert)
115+
assert.NoError(t, err)
116+
117+
// Certificate is in the middle
118+
_, cert = generateSelfSignedCert(t, time.Now())
119+
msp.opts.Roots = x509.NewCertPool()
120+
msp.opts.Roots.AddCert(cert)
121+
_, err = msp.getUniqueValidationChain(cert)
122+
assert.NoError(t, err)
123+
}
124+
125+
func generateSelfSignedCert(t *testing.T, now time.Time) (*ecdsa.PrivateKey, *x509.Certificate) {
126+
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
127+
assert.NoError(t, err)
128+
129+
// Generate a self-signed certificate
130+
testExtKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
131+
testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{2, 59, 1}}
132+
extraExtensionData := []byte("extra extension")
133+
commonName := "test.example.com"
134+
template := x509.Certificate{
135+
SerialNumber: big.NewInt(1),
136+
Subject: pkix.Name{
137+
CommonName: commonName,
138+
Organization: []string{"Σ Acme Co"},
139+
Country: []string{"US"},
140+
ExtraNames: []pkix.AttributeTypeAndValue{
141+
{
142+
Type: []int{2, 5, 4, 42},
143+
Value: "Gopher",
144+
},
145+
// This should override the Country, above.
146+
{
147+
Type: []int{2, 5, 4, 6},
148+
Value: "NL",
149+
},
150+
},
151+
},
152+
NotBefore: now.Add(-1 * time.Hour),
153+
NotAfter: now.Add(1 * time.Hour),
154+
SignatureAlgorithm: x509.ECDSAWithSHA256,
155+
SubjectKeyId: []byte{1, 2, 3, 4},
156+
KeyUsage: x509.KeyUsageCertSign,
157+
ExtKeyUsage: testExtKeyUsage,
158+
UnknownExtKeyUsage: testUnknownExtKeyUsage,
159+
BasicConstraintsValid: true,
160+
IsCA: true,
161+
OCSPServer: []string{"http://ocurrentBCCSP.example.com"},
162+
IssuingCertificateURL: []string{"http://crt.example.com/ca1.crt"},
163+
DNSNames: []string{"test.example.com"},
164+
EmailAddresses: []string{"[email protected]"},
165+
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
166+
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
167+
PermittedDNSDomains: []string{".example.com", "example.com"},
168+
CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
169+
ExtraExtensions: []pkix.Extension{
170+
{
171+
Id: []int{1, 2, 3, 4},
172+
Value: extraExtensionData,
173+
},
174+
},
175+
}
176+
certRaw, err := x509.CreateCertificate(rand.Reader, &template, &template, &k.PublicKey, k)
177+
assert.NoError(t, err)
178+
179+
cert, err := x509.ParseCertificate(certRaw)
180+
assert.NoError(t, err)
181+
182+
return k, cert
183+
}

msp/mspimpl.go

+18-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"fmt"
2828
"math/big"
2929
"reflect"
30+
"time"
3031

3132
"github.com/golang/protobuf/proto"
3233
"github.com/hyperledger/fabric/bccsp"
@@ -688,7 +689,7 @@ func (msp *bccspmsp) getUniqueValidationChain(cert *x509.Certificate) ([]*x509.C
688689
if msp.opts == nil {
689690
return nil, fmt.Errorf("The supplied identity has no verify options")
690691
}
691-
validationChains, err := cert.Verify(*(msp.opts))
692+
validationChains, err := cert.Verify(msp.getValidityOptsForCert(cert))
692693
if err != nil {
693694
return nil, fmt.Errorf("The supplied identity is not valid, Verify() returned %s", err)
694695
}
@@ -992,3 +993,19 @@ func (msp *bccspmsp) validateIdentityOUs(id *identity) error {
992993

993994
return nil
994995
}
996+
997+
func (msp *bccspmsp) getValidityOptsForCert(cert *x509.Certificate) x509.VerifyOptions {
998+
// First copy the opts to override the CurrentTime field
999+
// in order to make the certificate passing the expiration test
1000+
// independently from the real local current time.
1001+
// This is a temporary workaround for FAB-3678
1002+
1003+
var tempOpts x509.VerifyOptions
1004+
tempOpts.Roots = msp.opts.Roots
1005+
tempOpts.DNSName = msp.opts.DNSName
1006+
tempOpts.Intermediates = msp.opts.Intermediates
1007+
tempOpts.KeyUsages = msp.opts.KeyUsages
1008+
tempOpts.CurrentTime = cert.NotBefore.Add(time.Second)
1009+
1010+
return tempOpts
1011+
}

0 commit comments

Comments
 (0)