github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/gossip/comm/crypto.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 comm
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"crypto/elliptic"
    22  	"crypto/rand"
    23  	"crypto/tls"
    24  	"crypto/x509"
    25  	"encoding/pem"
    26  	"math/big"
    27  	"net"
    28  	"os"
    29  	"time"
    30  
    31  	"github.com/hyperledger/fabric/common/util"
    32  	"golang.org/x/net/context"
    33  	"google.golang.org/grpc/credentials"
    34  	"google.golang.org/grpc/peer"
    35  )
    36  
    37  func writeFile(filename string, keyType string, data []byte) error {
    38  	f, err := os.Create(filename)
    39  	if err != nil {
    40  		return err
    41  	}
    42  	defer f.Close()
    43  	return pem.Encode(f, &pem.Block{Type: keyType, Bytes: data})
    44  }
    45  
    46  func generateCertificates(privKeyFile string, certKeyFile string) error {
    47  	privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	sn, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
    53  	if err != nil {
    54  		return err
    55  	}
    56  	template := x509.Certificate{
    57  		KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    58  		SerialNumber: sn,
    59  		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    60  	}
    61  	rawBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	err = writeFile(certKeyFile, "CERTIFICATE", rawBytes)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	privBytes, err := x509.MarshalECPrivateKey(privateKey)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	err = writeFile(privKeyFile, "EC PRIVATE KEY", privBytes)
    74  	return err
    75  }
    76  
    77  func certHashFromRawCert(rawCert []byte) []byte {
    78  	if len(rawCert) == 0 {
    79  		return nil
    80  	}
    81  	return util.ComputeSHA256(rawCert)
    82  }
    83  
    84  // ExtractCertificateHash extracts the hash of the certificate from the stream
    85  func extractCertificateHashFromContext(ctx context.Context) []byte {
    86  	pr, extracted := peer.FromContext(ctx)
    87  	if !extracted {
    88  		return nil
    89  	}
    90  
    91  	authInfo := pr.AuthInfo
    92  	if authInfo == nil {
    93  		return nil
    94  	}
    95  
    96  	tlsInfo, isTLSConn := authInfo.(credentials.TLSInfo)
    97  	if !isTLSConn {
    98  		return nil
    99  	}
   100  	certs := tlsInfo.State.PeerCertificates
   101  	if len(certs) == 0 {
   102  		return nil
   103  	}
   104  	raw := certs[0].Raw
   105  	return certHashFromRawCert(raw)
   106  }
   107  
   108  type authCreds struct {
   109  	tlsCreds credentials.TransportCredentials
   110  }
   111  
   112  func (c authCreds) Info() credentials.ProtocolInfo {
   113  	return c.tlsCreds.Info()
   114  }
   115  
   116  func (c *authCreds) ClientHandshake(addr string, rawConn net.Conn, timeout time.Duration) (_ net.Conn, _ credentials.AuthInfo, err error) {
   117  	conn, auth, err := c.tlsCreds.ClientHandshake(addr, rawConn, timeout)
   118  	if auth == nil && conn != nil {
   119  		auth = credentials.TLSInfo{State: conn.(*tls.Conn).ConnectionState()}
   120  	}
   121  	return conn, auth, err
   122  }
   123  
   124  func (c *authCreds) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
   125  	return c.tlsCreds.ServerHandshake(rawConn)
   126  }