github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/msp/cert.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package msp
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/ecdsa"
    12  	"crypto/x509"
    13  	"crypto/x509/pkix"
    14  	"encoding/asn1"
    15  	"encoding/pem"
    16  	"errors"
    17  	"fmt"
    18  	"math/big"
    19  	"time"
    20  
    21  	"github.com/hyperledger/fabric/bccsp/sw"
    22  )
    23  
    24  type dsaSignature struct {
    25  	R, S *big.Int
    26  }
    27  
    28  type ecdsaSignature dsaSignature
    29  
    30  type validity struct {
    31  	NotBefore, NotAfter time.Time
    32  }
    33  
    34  type publicKeyInfo struct {
    35  	Raw       asn1.RawContent
    36  	Algorithm pkix.AlgorithmIdentifier
    37  	PublicKey asn1.BitString
    38  }
    39  
    40  type certificate struct {
    41  	Raw                asn1.RawContent
    42  	TBSCertificate     tbsCertificate
    43  	SignatureAlgorithm pkix.AlgorithmIdentifier
    44  	SignatureValue     asn1.BitString
    45  }
    46  
    47  type tbsCertificate struct {
    48  	Raw                asn1.RawContent
    49  	Version            int `asn1:"optional,explicit,default:0,tag:0"`
    50  	SerialNumber       *big.Int
    51  	SignatureAlgorithm pkix.AlgorithmIdentifier
    52  	Issuer             asn1.RawValue
    53  	Validity           validity
    54  	Subject            asn1.RawValue
    55  	PublicKey          publicKeyInfo
    56  	UniqueId           asn1.BitString   `asn1:"optional,tag:1"`
    57  	SubjectUniqueId    asn1.BitString   `asn1:"optional,tag:2"`
    58  	Extensions         []pkix.Extension `asn1:"optional,explicit,tag:3"`
    59  }
    60  
    61  func isECDSASignedCert(cert *x509.Certificate) bool {
    62  	return cert.SignatureAlgorithm == x509.ECDSAWithSHA1 ||
    63  		cert.SignatureAlgorithm == x509.ECDSAWithSHA256 ||
    64  		cert.SignatureAlgorithm == x509.ECDSAWithSHA384 ||
    65  		cert.SignatureAlgorithm == x509.ECDSAWithSHA512
    66  }
    67  
    68  // sanitizeECDSASignedCert checks that the signatures signing a cert
    69  // is in low-S. This is checked against the public key of parentCert.
    70  // If the signature is not in low-S, then a new certificate is generated
    71  // that is equals to cert but the signature that is in low-S.
    72  func sanitizeECDSASignedCert(cert *x509.Certificate, parentCert *x509.Certificate) (*x509.Certificate, error) {
    73  	if cert == nil {
    74  		return nil, errors.New("Certificate must be different from nil.")
    75  	}
    76  	if parentCert == nil {
    77  		return nil, errors.New("Parent certificate must be different from nil.")
    78  	}
    79  
    80  	expectedSig, err := sw.SignatureToLowS(parentCert.PublicKey.(*ecdsa.PublicKey), cert.Signature)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	// if sig == cert.Signature, nothing needs to be done
    86  	if bytes.Equal(cert.Signature, expectedSig) {
    87  		return cert, nil
    88  	}
    89  	// otherwise create a new certificate with the new signature
    90  
    91  	// 1. Unmarshal cert.Raw to get an instance of certificate,
    92  	//    the lower level interface that represent an x509 certificate
    93  	//    encoding
    94  	var newCert certificate
    95  	newCert, err = certFromX509Cert(cert)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	// 2. Change the signature
   101  	newCert.SignatureValue = asn1.BitString{Bytes: expectedSig, BitLength: len(expectedSig) * 8}
   102  
   103  	// 3. marshal again newCert. Raw must be nil
   104  	newCert.Raw = nil
   105  	newRaw, err := asn1.Marshal(newCert)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	// 4. parse newRaw to get an x509 certificate
   111  	return x509.ParseCertificate(newRaw)
   112  }
   113  
   114  func certFromX509Cert(cert *x509.Certificate) (certificate, error) {
   115  	var newCert certificate
   116  	_, err := asn1.Unmarshal(cert.Raw, &newCert)
   117  	if err != nil {
   118  		return certificate{}, err
   119  	}
   120  	return newCert, nil
   121  }
   122  
   123  // String returns a PEM representation of a certificate
   124  func (c certificate) String() string {
   125  	b, err := asn1.Marshal(c)
   126  	if err != nil {
   127  		return fmt.Sprintf("Failed marshaling cert: %v", err)
   128  	}
   129  	block := &pem.Block{
   130  		Bytes: b,
   131  		Type:  "CERTIFICATE",
   132  	}
   133  	b = pem.EncodeToMemory(block)
   134  	return string(b)
   135  }
   136  
   137  // certToPEM converts the given x509.Certificate to a PEM
   138  // encoded string
   139  func certToPEM(certificate *x509.Certificate) string {
   140  	cert, err := certFromX509Cert(certificate)
   141  	if err != nil {
   142  		mspIdentityLogger.Warning("Failed converting certificate to asn1", err)
   143  		return ""
   144  	}
   145  	return cert.String()
   146  }