Skip to content

Commit

Permalink
[FAB-4903] Use separate CA for TLS certs
Browse files Browse the repository at this point in the history
FAB-4626 separates out the trusted roots
for identity (signing) and for TLS.

cryptogen currently uses the same CA for
both.  With this change, cryptogen will
now create the updated MSP structure which
includes tlscacerts folder and adds support
for using separate CAs to generate identity
and TLS certs.

There is a TODO to actually leverage the
tlsCA but we cannot enable that until
we get FAB-4626 and this change merged

Change-Id: I32de28e2489fd8554274b9379c2572945569fc63
Signed-off-by: Gari Singh <gari.r.singh@gmail.com>
  • Loading branch information
mastersingh24 committed Jun 21, 2017
1 parent 3bc937e commit ec94ba5
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 81 deletions.
35 changes: 18 additions & 17 deletions common/tools/cryptogen/csp/csp.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,37 @@ import (
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/factory"
"github.com/hyperledger/fabric/bccsp/signer"
"github.com/hyperledger/fabric/bccsp/sw"
)

// GeneratePrivateKey creates a private key and stores it in keystorePath
func GeneratePrivateKey(keystorePath string) (bccsp.Key,
crypto.Signer, error) {

csp := factory.GetDefault()
var response error
var err error
var priv bccsp.Key
var s crypto.Signer

// generate a key
priv, err := csp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true})
response = err
opts := &factory.FactoryOpts{
ProviderName: "SW",
SwOpts: &factory.SwOpts{
HashFamily: "SHA2",
SecLevel: 256,

FileKeystore: &factory.FileKeystoreOpts{
KeyStorePath: keystorePath,
},
},
}
csp, err := factory.GetBCCSPFromOpts(opts)
if err == nil {
// write it to the keystore
ks, err := sw.NewFileBasedKeyStore(nil, keystorePath, false)
response = err
// generate a key
priv, err = csp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: false})
if err == nil {
err = ks.StoreKey(priv)
response = err
if err == nil {
// create a crypto.Signer
s, response = signer.New(csp, priv)
}
// create a crypto.Signer
s, err = signer.New(csp, priv)
}
}
return priv, s, response

return priv, s, err
}

func GetECPublicKey(priv bccsp.Key) (*ecdsa.PublicKey, error) {
Expand Down
48 changes: 34 additions & 14 deletions common/tools/cryptogen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,25 +381,35 @@ func generatePeerOrg(baseDir string, orgSpec OrgSpec) {
orgName := orgSpec.Domain

fmt.Println(orgName)
// generate CA
// generate CAs
orgDir := filepath.Join(baseDir, "peerOrganizations", orgName)
caDir := filepath.Join(orgDir, "ca")
tlsCADir := filepath.Join(orgDir, "tlsca")
mspDir := filepath.Join(orgDir, "msp")
peersDir := filepath.Join(orgDir, "peers")
usersDir := filepath.Join(orgDir, "users")
adminCertsDir := filepath.Join(mspDir, "admincerts")
rootCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName)
// generate signing CA
signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName)
if err != nil {
fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err)
fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err)
os.Exit(1)
}
err = msp.GenerateVerifyingMSP(mspDir, rootCA)
// generate TLS CA
tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName)
if err != nil {
fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err)
os.Exit(1)
}
// TODO remove the following line once MSP and peer changes are done
tlsCA = signCA
err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA)
if err != nil {
fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
os.Exit(1)
}

generateNodes(peersDir, orgSpec.Specs, rootCA)
generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA)

// TODO: add ability to specify usernames
users := []NodeSpec{}
Expand All @@ -416,7 +426,7 @@ func generatePeerOrg(baseDir string, orgSpec OrgSpec) {
}

users = append(users, adminUser)
generateNodes(usersDir, users, rootCA)
generateNodes(usersDir, users, signCA, tlsCA)

// copy the admin cert to the org's MSP admincerts
err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)
Expand Down Expand Up @@ -459,11 +469,11 @@ func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error {

}

func generateNodes(baseDir string, nodes []NodeSpec, rootCA *ca.CA) {
func generateNodes(baseDir string, nodes []NodeSpec, signCA *ca.CA, tlsCA *ca.CA) {

for _, node := range nodes {
nodeDir := filepath.Join(baseDir, node.CommonName)
err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, rootCA)
err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, signCA, tlsCA)
if err != nil {
fmt.Printf("Error generating local MSP for %s:\n%v\n", node, err)
os.Exit(1)
Expand All @@ -475,25 +485,35 @@ func generateOrdererOrg(baseDir string, orgSpec OrgSpec) {

orgName := orgSpec.Domain

// generate CA
// generate CAs
orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName)
caDir := filepath.Join(orgDir, "ca")
tlsCADir := filepath.Join(orgDir, "tlsca")
mspDir := filepath.Join(orgDir, "msp")
orderersDir := filepath.Join(orgDir, "orderers")
usersDir := filepath.Join(orgDir, "users")
adminCertsDir := filepath.Join(mspDir, "admincerts")
rootCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName)
// generate signing CA
signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName)
if err != nil {
fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err)
os.Exit(1)
}
// generate TLS CA
tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName)
if err != nil {
fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err)
fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err)
os.Exit(1)
}
err = msp.GenerateVerifyingMSP(mspDir, rootCA)
// TODO remove the following line once MSP and peer changes are done
tlsCA = signCA
err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA)
if err != nil {
fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
os.Exit(1)
}

generateNodes(orderersDir, orgSpec.Specs, rootCA)
generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA)

adminUser := NodeSpec{
CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
Expand All @@ -503,7 +523,7 @@ func generateOrdererOrg(baseDir string, orgSpec OrgSpec) {
users := []NodeSpec{}
// add an admin user
users = append(users, adminUser)
generateNodes(usersDir, users, rootCA)
generateNodes(usersDir, users, signCA, tlsCA)

// copy the admin cert to the org's MSP admincerts
err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)
Expand Down
68 changes: 28 additions & 40 deletions common/tools/cryptogen/msp/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ import (
"path/filepath"

"encoding/hex"
"io"

"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/factory"
"github.com/hyperledger/fabric/common/tools/cryptogen/ca"
"github.com/hyperledger/fabric/common/tools/cryptogen/csp"
)

func GenerateLocalMSP(baseDir, name string, sans []string, rootCA *ca.CA) error {
func GenerateLocalMSP(baseDir, name string, sans []string, signCA *ca.CA,
tlsCA *ca.CA) error {

// create folder structure
mspDir := filepath.Join(baseDir, "msp")
Expand Down Expand Up @@ -63,17 +63,22 @@ func GenerateLocalMSP(baseDir, name string, sans []string, rootCA *ca.CA) error
if err != nil {
return err
}
// generate X509 certificate
cert, err := rootCA.SignCertificate(filepath.Join(mspDir, "signcerts"),
// generate X509 certificate using signing CA
cert, err := signCA.SignCertificate(filepath.Join(mspDir, "signcerts"),
name, []string{}, ecPubKey, x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
if err != nil {
return err
}

// write artifacts to MSP folders

// the CA certificate goes into cacerts
err = x509Export(filepath.Join(mspDir, "cacerts", x509Filename(rootCA.Name)), rootCA.SignCert)
// the signing CA certificate goes into cacerts
err = x509Export(filepath.Join(mspDir, "cacerts", x509Filename(signCA.Name)), signCA.SignCert)
if err != nil {
return err
}
// the TLS CA certificate goes into tlscacerts
err = x509Export(filepath.Join(mspDir, "tlscacerts", x509Filename(tlsCA.Name)), tlsCA.SignCert)
if err != nil {
return err
}
Expand Down Expand Up @@ -104,22 +109,21 @@ func GenerateLocalMSP(baseDir, name string, sans []string, rootCA *ca.CA) error
if err != nil {
return err
}
// generate X509 certificate
_, err = rootCA.SignCertificate(filepath.Join(tlsDir),
// generate X509 certificate using TLS CA
_, err = tlsCA.SignCertificate(filepath.Join(tlsDir),
name, sans, tlsPubKey, x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
[]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth})
if err != nil {
return err
}
err = x509Export(filepath.Join(tlsDir, "ca.crt"), rootCA.SignCert)
err = x509Export(filepath.Join(tlsDir, "ca.crt"), tlsCA.SignCert)
if err != nil {
return err
}

// rename the generated TLS X509 cert
err = os.Rename(filepath.Join(tlsDir, x509Filename(name)),
filepath.Join(tlsDir, "server.crt"))
//err = x509Export(filepath.Join(tlsDir, "server.crt"), tlsCert)
if err != nil {
return err
}
Expand All @@ -132,19 +136,20 @@ func GenerateLocalMSP(baseDir, name string, sans []string, rootCA *ca.CA) error
return nil
}

func GenerateVerifyingMSP(baseDir string, rootCA *ca.CA) error {
func GenerateVerifyingMSP(baseDir string, signCA *ca.CA, tlsCA *ca.CA) error {

// create folder structure
// create folder structure and write artifacts to proper locations
err := createFolderStructure(baseDir, false)
if err == nil {
// write MSP cert to appropriate folders
//folders := []string{"cacerts", "signcerts"}
folders := []string{"cacerts"}
for _, folder := range folders {
err = x509Export(filepath.Join(baseDir, folder, x509Filename(rootCA.Name)), rootCA.SignCert)
if err != nil {
return err
}
// the signing CA certificate goes into cacerts
err = x509Export(filepath.Join(baseDir, "cacerts", x509Filename(signCA.Name)), signCA.SignCert)
if err != nil {
return err
}
// the TLS CA certificate goes into tlscacerts
err = x509Export(filepath.Join(baseDir, "tlscacerts", x509Filename(tlsCA.Name)), tlsCA.SignCert)
if err != nil {
return err
}
}

Expand All @@ -153,13 +158,14 @@ func GenerateVerifyingMSP(baseDir string, rootCA *ca.CA) error {
// cleared up anyway by copyAdminCert, but
// we leave a valid admin for now for the sake
// of unit tests
factory.InitFactories(nil)
bcsp := factory.GetDefault()
priv, err := bcsp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true})
ecPubKey, err := csp.GetECPublicKey(priv)
if err != nil {
return err
}
_, err = rootCA.SignCertificate(filepath.Join(baseDir, "admincerts"), rootCA.Name,
_, err = signCA.SignCertificate(filepath.Join(baseDir, "admincerts"), signCA.Name,
[]string{""}, ecPubKey, x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
if err != nil {
return err
Expand All @@ -175,6 +181,7 @@ func createFolderStructure(rootDir string, local bool) error {
folders = []string{
filepath.Join(rootDir, "admincerts"),
filepath.Join(rootDir, "cacerts"),
filepath.Join(rootDir, "tlscacerts"),
}
if local {
folders = append(folders, filepath.Join(rootDir, "keystore"),
Expand All @@ -199,25 +206,6 @@ func x509Export(path string, cert *x509.Certificate) error {
return pemExport(path, "CERTIFICATE", cert.Raw)
}

func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
cerr := out.Close()
if err != nil {
return err
}
return cerr
}

func keyExport(keystore, output string, key bccsp.Key) error {
id := hex.EncodeToString(key.SKI())

Expand Down
Loading

0 comments on commit ec94ba5

Please sign in to comment.