Skip to content

Commit

Permalink
[FAB-4138] Disable time-related cert expiration
Browse files Browse the repository at this point in the history
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 <adc@zurich.ibm.com>
  • Loading branch information
adecaro committed May 30, 2017
1 parent 27f996e commit 7ca901e
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 56 deletions.
144 changes: 89 additions & 55 deletions msp/cert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,63 +67,10 @@ func TestSanitizeCertInvalidInput(t *testing.T) {
}

func TestSanitizeCert(t *testing.T) {
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
assert.NoError(t, err)

var k *ecdsa.PrivateKey
var cert *x509.Certificate
for {
// Generate a self-signed certificate
testExtKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{2, 59, 1}}
extraExtensionData := []byte("extra extension")
commonName := "test.example.com"
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: commonName,
Organization: []string{"Σ Acme Co"},
Country: []string{"US"},
ExtraNames: []pkix.AttributeTypeAndValue{
{
Type: []int{2, 5, 4, 42},
Value: "Gopher",
},
// This should override the Country, above.
{
Type: []int{2, 5, 4, 6},
Value: "NL",
},
},
},
NotBefore: time.Now().Add(-1 * time.Hour),
NotAfter: time.Now().Add(1 * time.Hour),
SignatureAlgorithm: x509.ECDSAWithSHA256,
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: x509.KeyUsageCertSign,
ExtKeyUsage: testExtKeyUsage,
UnknownExtKeyUsage: testUnknownExtKeyUsage,
BasicConstraintsValid: true,
IsCA: true,
OCSPServer: []string{"http://ocurrentBCCSP.example.com"},
IssuingCertificateURL: []string{"http://crt.example.com/ca1.crt"},
DNSNames: []string{"test.example.com"},
EmailAddresses: []string{"gopher@golang.org"},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
PermittedDNSDomains: []string{".example.com", "example.com"},
CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
ExtraExtensions: []pkix.Extension{
{
Id: []int{1, 2, 3, 4},
Value: extraExtensionData,
},
},
}
certRaw, err := x509.CreateCertificate(rand.Reader, &template, &template, &k.PublicKey, k)
assert.NoError(t, err)

cert, err = x509.ParseCertificate(certRaw)
assert.NoError(t, err)
k, cert = generateSelfSignedCert(t, time.Now())

_, s, err := sw.UnmarshalECDSASignature(cert.Signature)
assert.NoError(t, err)
Expand All @@ -147,3 +94,90 @@ func TestSanitizeCert(t *testing.T) {
assert.NoError(t, err)
assert.True(t, lowS)
}

func TestCertExpiration(t *testing.T) {
msp := &bccspmsp{}
msp.opts = &x509.VerifyOptions{}
msp.opts.DNSName = "test.example.com"

// Certificate is in the future
_, cert := generateSelfSignedCert(t, time.Now().Add(24*time.Hour))
msp.opts.Roots = x509.NewCertPool()
msp.opts.Roots.AddCert(cert)
_, err := msp.getUniqueValidationChain(cert)
assert.NoError(t, err)

// Certificate is in the past
_, cert = generateSelfSignedCert(t, time.Now().Add(-24*time.Hour))
msp.opts.Roots = x509.NewCertPool()
msp.opts.Roots.AddCert(cert)
_, err = msp.getUniqueValidationChain(cert)
assert.NoError(t, err)

// Certificate is in the middle
_, cert = generateSelfSignedCert(t, time.Now())
msp.opts.Roots = x509.NewCertPool()
msp.opts.Roots.AddCert(cert)
_, err = msp.getUniqueValidationChain(cert)
assert.NoError(t, err)
}

func generateSelfSignedCert(t *testing.T, now time.Time) (*ecdsa.PrivateKey, *x509.Certificate) {
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
assert.NoError(t, err)

// Generate a self-signed certificate
testExtKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{2, 59, 1}}
extraExtensionData := []byte("extra extension")
commonName := "test.example.com"
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: commonName,
Organization: []string{"Σ Acme Co"},
Country: []string{"US"},
ExtraNames: []pkix.AttributeTypeAndValue{
{
Type: []int{2, 5, 4, 42},
Value: "Gopher",
},
// This should override the Country, above.
{
Type: []int{2, 5, 4, 6},
Value: "NL",
},
},
},
NotBefore: now.Add(-1 * time.Hour),
NotAfter: now.Add(1 * time.Hour),
SignatureAlgorithm: x509.ECDSAWithSHA256,
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: x509.KeyUsageCertSign,
ExtKeyUsage: testExtKeyUsage,
UnknownExtKeyUsage: testUnknownExtKeyUsage,
BasicConstraintsValid: true,
IsCA: true,
OCSPServer: []string{"http://ocurrentBCCSP.example.com"},
IssuingCertificateURL: []string{"http://crt.example.com/ca1.crt"},
DNSNames: []string{"test.example.com"},
EmailAddresses: []string{"gopher@golang.org"},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
PermittedDNSDomains: []string{".example.com", "example.com"},
CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
ExtraExtensions: []pkix.Extension{
{
Id: []int{1, 2, 3, 4},
Value: extraExtensionData,
},
},
}
certRaw, err := x509.CreateCertificate(rand.Reader, &template, &template, &k.PublicKey, k)
assert.NoError(t, err)

cert, err := x509.ParseCertificate(certRaw)
assert.NoError(t, err)

return k, cert
}
19 changes: 18 additions & 1 deletion msp/mspimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"fmt"
"math/big"
"reflect"
"time"

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

return nil
}

func (msp *bccspmsp) getValidityOptsForCert(cert *x509.Certificate) x509.VerifyOptions {
// First copy the opts to override the CurrentTime field
// in order to make the certificate passing the expiration test
// independently from the real local current time.
// This is a temporary workaround for FAB-3678

var tempOpts x509.VerifyOptions
tempOpts.Roots = msp.opts.Roots
tempOpts.DNSName = msp.opts.DNSName
tempOpts.Intermediates = msp.opts.Intermediates
tempOpts.KeyUsages = msp.opts.KeyUsages
tempOpts.CurrentTime = cert.NotBefore.Add(time.Second)

return tempOpts
}

0 comments on commit 7ca901e

Please sign in to comment.