Skip to content

Commit

Permalink
[FAB-9009]Cert expiry check
Browse files Browse the repository at this point in the history
Change-Id: Ic421384fce80ed8be392c8e3bf25ae2059415deb
Signed-off-by: biljana lukovic <[email protected]>
  • Loading branch information
biljanaLukovic committed Mar 22, 2018
1 parent 38d16da commit 2a697ce
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 1 deletion.
18 changes: 18 additions & 0 deletions pkg/client/common/verifier/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ SPDX-License-Identifier: Apache-2.0
package verifier

import (
"crypto/x509"
"time"

"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/status"
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common"
Expand Down Expand Up @@ -54,3 +57,18 @@ func (v *Signature) Verify(response *fab.TransactionProposalResponse) error {
func (v *Signature) Match(response []*fab.TransactionProposalResponse) error {
return nil
}

//ValidateCertificateDates used to verify if certificate was expired or not valid until later date
func ValidateCertificateDates(cert *x509.Certificate) error {
if cert == nil {
return errors.New("Nil certificate has been passed in")
}
if time.Now().UTC().Before(cert.NotBefore) {
return errors.New("Certificate provided is not valid until later date")
}

if time.Now().UTC().After(cert.NotAfter) {
return errors.New("Certificate provided has expired")
}
return nil
}
32 changes: 31 additions & 1 deletion pkg/fab/channel/membership/membership.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/verifier"
"github.com/hyperledger/fabric-sdk-go/pkg/common/logging"
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/core"
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
Expand Down Expand Up @@ -40,11 +41,16 @@ func New(ctx Context, cfg fab.ChannelCfg) (fab.ChannelMembership, error) {
}

func (i *identityImpl) Validate(serializedID []byte) error {
id, err := i.mspManager.DeserializeIdentity(serializedID)
err := areCertDatesValid(serializedID)
if err != nil {
logger.Errorf("Cert error %v", err)
return err
}

id, err := i.mspManager.DeserializeIdentity(serializedID)
if err != nil {
return err
}
return id.Validate()
}

Expand All @@ -57,6 +63,30 @@ func (i *identityImpl) Verify(serializedID []byte, msg []byte, sig []byte) error
return id.Verify(msg, sig)
}

func areCertDatesValid(serializedID []byte) error {

sID := &mb.SerializedIdentity{}
err := proto.Unmarshal(serializedID, sID)
if err != nil {
return errors.Wrap(err, "could not deserialize a SerializedIdentity")
}

bl, _ := pem.Decode(sID.IdBytes)
if bl == nil {
return errors.New("could not decode the PEM structure")
}
cert, err := x509.ParseCertificate(bl.Bytes)
if err != nil {
return err
}
err = verifier.ValidateCertificateDates(cert)
if err != nil {
logger.Warnf("Certificate error '%v' for cert '%v'", err, cert.SerialNumber)
return err
}
return nil
}

func createMSPManager(ctx Context, cfg fab.ChannelCfg) (msp.MSPManager, error) {
mspManager := msp.NewMSPManager()
if len(cfg.MSPs()) > 0 {
Expand Down
149 changes: 149 additions & 0 deletions pkg/fab/channel/membership/membership_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,21 @@ SPDX-License-Identifier: Apache-2.0
package membership

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"log"
"math/big"
"strings"
"testing"
"time"

"fmt"

"encoding/pem"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric-sdk-go/pkg/fab/mocks"
Expand Down Expand Up @@ -69,6 +82,42 @@ func TestRevokedCertificate(t *testing.T) {

}

//TestExpiredCertificate
func TestCertificateDates(t *testing.T) {
var err error
goodMSPID := "GoodMSP"
ctx := mocks.NewMockProviderContext()
cfg := mocks.NewMockChannelCfg("")
if err != nil {
t.Fatalf("Error %v", err)
}
// Test good config input
cfg.MockMSPs = []*mb.MSPConfig{buildMSPConfig(goodMSPID, []byte(orgTwoCA))}
m, err := New(Context{Providers: ctx}, cfg)
assert.Nil(t, err)
assert.NotNil(t, m)

// Certificate is in the future
cert := generateSelfSignedCert(t, time.Now().Add(24*time.Hour))
sID := &mb.SerializedIdentity{Mspid: goodMSPID, IdBytes: []byte(cert)}
goodEndorser, err := proto.Marshal(sID)
assert.Nil(t, err)
err = m.Validate(goodEndorser)
if !strings.Contains(err.Error(), "Certificate provided is not valid until later date") {
t.Fatalf("Expected error 'Certificate provided is not valid until later date'")
}

// Certificate is in the past
cert = generateSelfSignedCert(t, time.Now().Add(-24*time.Hour))
sID = &mb.SerializedIdentity{Mspid: goodMSPID, IdBytes: []byte(cert)}
goodEndorser, err = proto.Marshal(sID)
assert.Nil(t, err)
err = m.Validate(goodEndorser)
if !strings.Contains(err.Error(), "Certificate provided has expired") {
t.Fatalf("Expected error 'Certificate provided has expired'")
}
}

func TestNewMembership(t *testing.T) {
goodMSPID := "GoodMSP"
badMSPID := "BadMSP"
Expand Down Expand Up @@ -226,3 +275,103 @@ Vnsqn32+nmoGO6dn1CvwtUTBMAoGCCqGSM49BAMCA0gAMEUCIQCH8+Vw0L38dv/v
9gWvLhQv69q2bS0FBiAFwR4M17Z/2QIgH5W6rmsItiwa7nD0eZyiGmCzzQXW01b4
5fDo4hNhETQ=
-----END CERTIFICATE-----`

var expiredCertificate = `-----BEGIN CERTIFICATE-----
MIIB/TCCAaOgAwIBAgIBATAKBggqhkjOPQQDAjBOMRMwEQYDVQQKDArOoyBBY21l
IENvMRkwFwYDVQQDExB0ZXN0LmV4YW1wbGUuY29tMQ8wDQYDVQQqEwZHb3BoZXIx
CzAJBgNVBAYTAk5MMB4XDTE4MDMyMDE5NDE0NVoXDTE4MDMyMDIxNDE0NVowTjET
MBEGA1UECgwKzqMgQWNtZSBDbzEZMBcGA1UEAxMQdGVzdC5leGFtcGxlLmNvbTEP
MA0GA1UEKhMGR29waGVyMQswCQYDVQQGEwJOTDBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABKuBweTX12BpJ4zbhYflCWUnEAWLmOsPohPOF38Bf2efHET0+MjD3fqR
FAXOxTxeDXCRJOrEavnimpFUZCAOxvCjcjBwMA4GA1UdDwEB/wQEAwICBDAmBgNV
HSUEHzAdBggrBgEFBQcDAgYIKwYBBQUHAwEGAioDBgOBCwEwDwYDVR0TAQH/BAUw
AwEB/zANBgNVHQ4EBgQEAQIDBDAWBgMqAwQED2V4dHJhIGV4dGVuc2lvbjAKBggq
hkjOPQQDAgNIADBFAiA9WgC9FDstiVmU6JreuN9AKGDhOjuC069A5A5K9fNLEwIh
AJ4v8ZQD4r2oPaiJtxJOPLx4OYGEPDUWmhdj3MkWUBZd
-----END CERTIFICATE-----`

type validity struct {
NotBefore, NotAfter time.Time
}

type publicKeyInfo struct {
Raw asn1.RawContent
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}

type tbsCertificate struct {
Raw asn1.RawContent
Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
Issuer asn1.RawValue
Validity validity
Subject asn1.RawValue
PublicKey publicKeyInfo
UniqueID asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueID asn1.BitString `asn1:"optional,tag:2"`
Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}

type certificate struct {
Raw asn1.RawContent
TBSCertificate tbsCertificate
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}

// encodeCertToMemory returns a PEM representation of a certificate
func encodeCertToMemory(c certificate) string {
b, err := asn1.Marshal(c)
if err != nil {
return fmt.Sprintf("Failed marshaling cert: %v", err)
}
block := &pem.Block{
Bytes: b,
Type: "CERTIFICATE",
}
b = pem.EncodeToMemory(block)
return string(b)
}

func generateSelfSignedCert(t *testing.T, now time.Time) string {
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 := "securekey.com"
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: commonName,
Organization: []string{"SK"},
Country: []string{"CA"},
},
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,
}
certRaw, err := x509.CreateCertificate(rand.Reader, &template, &template, &k.PublicKey, k)
assert.NoError(t, err)
if err != nil {
log.Fatalf("Failed to create certificate: %s", err)
}

var newCert certificate
_, err = asn1.Unmarshal(certRaw, &newCert)
if err != nil {
log.Fatalf("Failed to unmarshal certificate: %s", err)
}
return encodeCertToMemory(newCert)

}

0 comments on commit 2a697ce

Please sign in to comment.