Commit da4ddd05 authored by yacovm's avatar yacovm
Browse files

[FAB-14852] Validate TLS certs are x509 encoded



This change set adds validation that the TLS certificates
in a config update are x509 certificates.

Change-Id: Id68202ff1ae47970d76e8435f271329da7ebfaec
Signed-off-by: default avataryacovm <yacovm@il.ibm.com>
parent f9975970
......@@ -1751,15 +1751,26 @@ var _ = Describe("Chain", func() {
"empty consenter set"))
})
It("fails with invalid certificate", func() {
It("fails with invalid certificate for non PEM certificates", func() {
metadata := &raftprotos.ConfigMetadata{Options: options}
for _, consenter := range consenters {
metadata.Consenters = append(metadata.Consenters, consenter)
}
metadata.Consenters[0].ClientTlsCert = []byte("Hello")
metadata.Consenters[0].ClientTlsCert = []byte("hello")
Expect(c1.Configure(createChannelEnv(metadata), 0)).To(MatchError(
"invalid client TLS cert: Hello"))
"client TLS certificate is not PEM encoded: hello"))
})
It("fails with invalid certificate for malformed certificates", func() {
metadata := &raftprotos.ConfigMetadata{Options: options}
for _, consenter := range consenters {
metadata.Consenters = append(metadata.Consenters, consenter)
}
metadata.Consenters[0].ServerTlsCert = pem.EncodeToMemory(&pem.Block{Bytes: []byte("hello")})
Expect(c1.Configure(createChannelEnv(metadata), 0).Error()).To(ContainSubstring(
"server TLS certificate has invalid ASN1 structure"))
})
It("fails with extra consenter", func() {
......@@ -1830,7 +1841,7 @@ var _ = Describe("Chain", func() {
c1.cutter.CutNext = true
By("sending config transaction")
Expect(c1.Configure(configEnv, 0)).To(MatchError("invalid server TLS cert: hello"))
Expect(c1.Configure(configEnv, 0)).To(MatchError("server TLS certificate is not PEM encoded: hello"))
})
It("can rotate certificate by adding and removing 1 node in one config update", func() {
......
......@@ -8,6 +8,7 @@ package etcdraft
import (
"bytes"
"crypto/x509"
"encoding/pem"
"fmt"
"sync"
......@@ -416,12 +417,11 @@ func CheckConfigMetadata(metadata *etcdraft.ConfigMetadata) error {
// sanity check of certificates
for _, consenter := range metadata.Consenters {
if bl, _ := pem.Decode(consenter.ServerTlsCert); bl == nil {
return errors.Errorf("invalid server TLS cert: %s", string(consenter.ServerTlsCert))
if err := validateCert(consenter.ServerTlsCert, "server"); err != nil {
return err
}
if bl, _ := pem.Decode(consenter.ClientTlsCert); bl == nil {
return errors.Errorf("invalid client TLS cert: %s", string(consenter.ClientTlsCert))
if err := validateCert(consenter.ClientTlsCert, "client"); err != nil {
return err
}
}
......@@ -432,6 +432,19 @@ func CheckConfigMetadata(metadata *etcdraft.ConfigMetadata) error {
return nil
}
func validateCert(pemData []byte, certRole string) error {
bl, _ := pem.Decode(pemData)
if bl == nil {
return errors.Errorf("%s TLS certificate is not PEM encoded: %s", certRole, string(pemData))
}
if _, err := x509.ParseCertificate(bl.Bytes); err != nil {
return errors.Errorf("%s TLS certificate has invalid ASN1 structure, %v: %s", certRole, err, string(pemData))
}
return nil
}
// ConsenterCertificate denotes a TLS certificate of a consenter
type ConsenterCertificate []byte
......@@ -467,16 +480,6 @@ func (conCert ConsenterCertificate) IsConsenterOfChannel(configBlock *common.Blo
return cluster.ErrNotInChannel
}
// SliceOfConsentersIDs converts maps of consenters into slice of consenters ids
func SliceOfConsentersIDs(consenters map[uint64]*etcdraft.Consenter) []uint64 {
result := make([]uint64, 0)
for id := range consenters {
result = append(result, id)
}
return result
}
// NodeExists returns trues if node id exists in the slice
// and false otherwise
func NodeExists(id uint64, nodes []uint64) bool {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment