-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FAB-2545] Add tool to create various crypto configs
https://jira.hyperledger.org/browse/FAB-2545 In order to get a test (or even real) system running, there is a lot of cryptographic material required: - root certificates for CAs (e.g. fabric-ca) - MSPs for organizations running peers - Local MSPs for peers - MSPs for ordererer organizations - Local MSPs for ordering nodes This CR adds a tool named "cryptogen" which will create these artifacts for you. It allows you to specify the number of peer organizations, the number of peers per organization and the number of ordering nodes (shims). It currently only creates a single orderer organization. To run, "./cryptogen" and it will display the command line options Change-Id: I15f135dc2893f7492566eb8ac5d02b2f4963ccd3 Signed-off-by: Gari Singh <gari.r.singh@gmail.com>
- Loading branch information
1 parent
56c9e4c
commit be91ccc
Showing
7 changed files
with
808 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
Copyright IBM Corp. 2017 All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
package ca_test | ||
|
||
import ( | ||
"crypto/x509" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/hyperledger/fabric/common/tools/cryptogen/ca" | ||
"github.com/hyperledger/fabric/common/tools/cryptogen/csp" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
const ( | ||
testCAName = "root0" | ||
testCA2Name = "root1" | ||
testName = "cert0" | ||
) | ||
|
||
var testDir = filepath.Join(os.TempDir(), "ca-test") | ||
|
||
func TestNewCA(t *testing.T) { | ||
|
||
caDir := filepath.Join(testDir, "ca") | ||
rootCA, err := ca.NewCA(caDir, testCAName) | ||
assert.NoError(t, err, "Error generating CA") | ||
assert.NotNil(t, rootCA, "Failed to return CA") | ||
assert.NotNil(t, rootCA.Signer, | ||
"rootCA.Signer should not be empty") | ||
assert.IsType(t, &x509.Certificate{}, rootCA.SignCert, | ||
"rootCA.SignCert should be type x509.Certificate") | ||
|
||
// check to make sure the root public key was stored | ||
pemFile := filepath.Join(caDir, testCAName+"-cert.pem") | ||
assert.Equal(t, true, checkForFile(pemFile), | ||
"Expected to find file "+pemFile) | ||
cleanup(testDir) | ||
|
||
} | ||
|
||
func TestGenerateSignedCertificate(t *testing.T) { | ||
|
||
caDir := filepath.Join(testDir, "ca") | ||
certDir := filepath.Join(testDir, "certs") | ||
// generate private key | ||
priv, _, err := csp.GeneratePrivateKey(certDir) | ||
assert.NoError(t, err, "Failed to generate signed certificate") | ||
|
||
// get EC public key | ||
ecPubKey, err := csp.GetECPublicKey(priv) | ||
assert.NoError(t, err, "Failed to generate signed certificate") | ||
assert.NotNil(t, ecPubKey, "Failed to generate signed certificate") | ||
|
||
// create our CA | ||
rootCA, err := ca.NewCA(caDir, testCA2Name) | ||
assert.NoError(t, err, "Error generating CA") | ||
|
||
err = rootCA.SignCertificate(certDir, testName, ecPubKey) | ||
assert.NoError(t, err, "Failed to generate signed certificate") | ||
|
||
// check to make sure the signed public key was stored | ||
pemFile := filepath.Join(certDir, testName+"-cert.pem") | ||
assert.Equal(t, true, checkForFile(pemFile), | ||
"Expected to find file "+pemFile) | ||
cleanup(testDir) | ||
|
||
} | ||
|
||
func cleanup(dir string) { | ||
os.RemoveAll(dir) | ||
} | ||
|
||
func checkForFile(file string) bool { | ||
if _, err := os.Stat(file); os.IsNotExist(err) { | ||
return false | ||
} | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/* | ||
Copyright IBM Corp. 2017 All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
package ca | ||
|
||
import ( | ||
"crypto" | ||
"crypto/ecdsa" | ||
"crypto/rand" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"encoding/pem" | ||
"math/big" | ||
"os" | ||
"time" | ||
|
||
"path/filepath" | ||
|
||
"github.com/hyperledger/fabric/common/tools/cryptogen/csp" | ||
) | ||
|
||
type CA struct { | ||
Name string | ||
//SignKey *ecdsa.PrivateKey | ||
Signer crypto.Signer | ||
SignCert *x509.Certificate | ||
} | ||
|
||
// NewCA creates an instance of CA and saves the signing key pair in | ||
// baseDir/name | ||
func NewCA(baseDir, name string) (*CA, error) { | ||
|
||
err := os.MkdirAll(baseDir, 0755) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
//key, err := genKeyECDSA(caDir, name) | ||
priv, signer, err := csp.GeneratePrivateKey(baseDir) | ||
// get public signing certificate | ||
ecPubKey, err := csp.GetECPublicKey(priv) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
template, err := x509Template() | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
//this is a CA | ||
template.IsCA = true | ||
template.KeyUsage |= x509.KeyUsageCertSign | x509.KeyUsageCRLSign | ||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny} | ||
|
||
//set the organization for the subject | ||
subject := subjectTemplate() | ||
subject.Organization = []string{name} | ||
subject.CommonName = name | ||
|
||
template.Subject = subject | ||
template.SubjectKeyId = priv.SKI() | ||
|
||
x509Cert, err := genCertificateECDSA(baseDir, name, &template, &template, | ||
ecPubKey, signer) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
ca := &CA{ | ||
Name: name, | ||
Signer: signer, | ||
SignCert: x509Cert, | ||
} | ||
|
||
return ca, nil | ||
} | ||
|
||
// SignCertificate creates a signed certificate based on a built-in template | ||
// and saves it in baseDir/name | ||
func (ca *CA) SignCertificate(baseDir, name string, pub *ecdsa.PublicKey) error { | ||
|
||
template, err := x509Template() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} | ||
|
||
//set the organization for the subject | ||
subject := subjectTemplate() | ||
subject.CommonName = name | ||
|
||
template.Subject = subject | ||
|
||
_, err = genCertificateECDSA(baseDir, name, &template, ca.SignCert, | ||
pub, ca.Signer) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// default template for X509 subject | ||
func subjectTemplate() pkix.Name { | ||
return pkix.Name{ | ||
Country: []string{"US"}, | ||
Locality: []string{"San Francisco"}, | ||
Province: []string{"California"}, | ||
} | ||
} | ||
|
||
// default template for X509 certificates | ||
func x509Template() (x509.Certificate, error) { | ||
|
||
//generate a serial number | ||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) | ||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | ||
if err != nil { | ||
return x509.Certificate{}, err | ||
} | ||
|
||
now := time.Now() | ||
//basic template to use | ||
x509 := x509.Certificate{ | ||
SerialNumber: serialNumber, | ||
NotBefore: now, | ||
NotAfter: now.Add(3650 * 24 * time.Hour), //~ten years | ||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, | ||
BasicConstraintsValid: true, | ||
} | ||
return x509, nil | ||
|
||
} | ||
|
||
// generate a signed X509 certficate using ECDSA | ||
func genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey, | ||
priv interface{}) (*x509.Certificate, error) { | ||
|
||
//create the x509 public cert | ||
certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
//write cert out to file | ||
fileName := filepath.Join(baseDir, name+"-cert.pem") | ||
certFile, err := os.Create(fileName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
//pem encode the cert | ||
err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) | ||
certFile.Close() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
x509Cert, err := x509.ParseCertificate(certBytes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return x509Cert, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
Copyright IBM Corp. 2017 All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
package csp | ||
|
||
import ( | ||
"crypto" | ||
"crypto/ecdsa" | ||
"crypto/x509" | ||
|
||
"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() | ||
|
||
// generate a key | ||
priv, err := csp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true}) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
// write it to the keystore | ||
ks, err := sw.NewFileBasedKeyStore(nil, keystorePath, false) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
err = ks.StoreKey(priv) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
// create a crypto.Signer | ||
signer := &signer.CryptoSigner{} | ||
err = signer.Init(csp, priv) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
return priv, signer, nil | ||
|
||
} | ||
|
||
func GetECPublicKey(priv bccsp.Key) (*ecdsa.PublicKey, error) { | ||
|
||
// get the public key | ||
pubKey, err := priv.PublicKey() | ||
if err != nil { | ||
return nil, err | ||
} | ||
// marshal to bytes | ||
pubKeyBytes, err := pubKey.Bytes() | ||
if err != nil { | ||
return nil, err | ||
} | ||
// unmarshal using pkix | ||
ecPubKey, err := x509.ParsePKIXPublicKey(pubKeyBytes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return ecPubKey.(*ecdsa.PublicKey), nil | ||
} |
Oops, something went wrong.