github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/orderer/sbft/connection/connection.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package connection
    18  
    19  import (
    20  	"crypto/sha256"
    21  	"crypto/tls"
    22  	"crypto/x509"
    23  	"fmt"
    24  	"net"
    25  
    26  	"google.golang.org/grpc"
    27  	"google.golang.org/grpc/credentials"
    28  	"google.golang.org/grpc/peer"
    29  	"google.golang.org/grpc/transport"
    30  )
    31  
    32  type PeerInfo struct {
    33  	addr string
    34  	cert *x509.Certificate
    35  	cp   *x509.CertPool
    36  }
    37  
    38  type Manager struct {
    39  	Server    *grpc.Server
    40  	Listener  net.Listener
    41  	Self      PeerInfo
    42  	tlsConfig *tls.Config
    43  	Cert      *tls.Certificate
    44  }
    45  
    46  func New(addr string, certFile string, keyFile string) (_ *Manager, err error) {
    47  	c := &Manager{}
    48  
    49  	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	c.Cert = &cert
    59  	c.Self, err = NewPeerInfo("", cert.Certificate[0])
    60  
    61  	c.tlsConfig = &tls.Config{
    62  		Certificates:       []tls.Certificate{cert},
    63  		ClientAuth:         tls.RequestClientCert,
    64  		InsecureSkipVerify: true,
    65  	}
    66  
    67  	c.Listener, err = net.Listen("tcp", addr)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	serverTls := c.tlsConfig
    73  	serverTls.ServerName = addr
    74  	c.Server = grpc.NewServer(grpc.Creds(credentials.NewTLS(serverTls)))
    75  	go c.Server.Serve(c.Listener)
    76  	return c, nil
    77  }
    78  
    79  func (c *Manager) DialPeer(peer PeerInfo, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
    80  	return dialPeer(&c.tlsConfig.Certificates[0], peer, opts...)
    81  }
    82  
    83  // to check client: credentials.FromContext() -> AuthInfo
    84  
    85  type patchedAuthenticator struct {
    86  	credentials.TransportCredentials
    87  	pinnedCert    *x509.Certificate
    88  	tunneledError error
    89  }
    90  
    91  func dialPeer(cert *tls.Certificate, peer PeerInfo, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
    92  	clientTLS := &tls.Config{InsecureSkipVerify: true}
    93  	if cert != nil {
    94  		clientTLS.Certificates = []tls.Certificate{*cert}
    95  	}
    96  
    97  	creds := credentials.NewTLS(clientTLS)
    98  	patchedCreds := &patchedAuthenticator{
    99  		TransportCredentials: creds,
   100  		pinnedCert:           peer.cert,
   101  	}
   102  	opts = append(opts, grpc.WithTransportCredentials(patchedCreds))
   103  	conn, err := grpc.Dial(peer.addr, opts...)
   104  	if err != nil {
   105  		if patchedCreds.tunneledError != nil {
   106  			err = patchedCreds.tunneledError
   107  		}
   108  		return nil, err
   109  	}
   110  
   111  	return conn, nil
   112  }
   113  
   114  func DialPeer(peer PeerInfo, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
   115  	return dialPeer(nil, peer, opts...)
   116  }
   117  
   118  func GetPeerInfo(s grpc.Stream) PeerInfo {
   119  	var pi PeerInfo
   120  
   121  	ctx := s.Context()
   122  	trs, ok := transport.StreamFromContext(ctx)
   123  	if ok {
   124  		pi.addr = trs.ServerTransport().RemoteAddr().String()
   125  	}
   126  
   127  	p, _ := peer.FromContext(ctx)
   128  	switch creds := p.AuthInfo.(type) {
   129  	case credentials.TLSInfo:
   130  		state := creds.State
   131  		if len(state.PeerCertificates) > 0 {
   132  			pi.cert = state.PeerCertificates[0]
   133  		}
   134  	}
   135  
   136  	return pi
   137  }
   138  
   139  func NewPeerInfo(addr string, cert []byte) (_ PeerInfo, err error) {
   140  	var p PeerInfo
   141  
   142  	p.addr = addr
   143  	p.cert, err = x509.ParseCertificate(cert)
   144  	if err != nil {
   145  		return
   146  	}
   147  	p.cp = x509.NewCertPool()
   148  	p.cp.AddCert(p.cert)
   149  	return p, nil
   150  }
   151  
   152  func (pi *PeerInfo) Fingerprint() string {
   153  	return fmt.Sprintf("%x", sha256.Sum256(pi.cert.Raw))
   154  }
   155  
   156  func (pi *PeerInfo) Cert() *x509.Certificate {
   157  	cert := *pi.cert
   158  	return &cert
   159  }
   160  
   161  func (pi PeerInfo) String() string {
   162  	return fmt.Sprintf("%.6s [%s]", pi.Fingerprint(), pi.addr)
   163  }