Skip to content

Commit be91ccc

Browse files
committed
[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 <[email protected]>
1 parent 56c9e4c commit be91ccc

File tree

7 files changed

+808
-0
lines changed

7 files changed

+808
-0
lines changed

common/tools/cryptogen/ca/ca_test.go

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
Copyright IBM Corp. 2017 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+
package ca_test
17+
18+
import (
19+
"crypto/x509"
20+
"os"
21+
"path/filepath"
22+
"testing"
23+
24+
"github.com/hyperledger/fabric/common/tools/cryptogen/ca"
25+
"github.com/hyperledger/fabric/common/tools/cryptogen/csp"
26+
"github.com/stretchr/testify/assert"
27+
)
28+
29+
const (
30+
testCAName = "root0"
31+
testCA2Name = "root1"
32+
testName = "cert0"
33+
)
34+
35+
var testDir = filepath.Join(os.TempDir(), "ca-test")
36+
37+
func TestNewCA(t *testing.T) {
38+
39+
caDir := filepath.Join(testDir, "ca")
40+
rootCA, err := ca.NewCA(caDir, testCAName)
41+
assert.NoError(t, err, "Error generating CA")
42+
assert.NotNil(t, rootCA, "Failed to return CA")
43+
assert.NotNil(t, rootCA.Signer,
44+
"rootCA.Signer should not be empty")
45+
assert.IsType(t, &x509.Certificate{}, rootCA.SignCert,
46+
"rootCA.SignCert should be type x509.Certificate")
47+
48+
// check to make sure the root public key was stored
49+
pemFile := filepath.Join(caDir, testCAName+"-cert.pem")
50+
assert.Equal(t, true, checkForFile(pemFile),
51+
"Expected to find file "+pemFile)
52+
cleanup(testDir)
53+
54+
}
55+
56+
func TestGenerateSignedCertificate(t *testing.T) {
57+
58+
caDir := filepath.Join(testDir, "ca")
59+
certDir := filepath.Join(testDir, "certs")
60+
// generate private key
61+
priv, _, err := csp.GeneratePrivateKey(certDir)
62+
assert.NoError(t, err, "Failed to generate signed certificate")
63+
64+
// get EC public key
65+
ecPubKey, err := csp.GetECPublicKey(priv)
66+
assert.NoError(t, err, "Failed to generate signed certificate")
67+
assert.NotNil(t, ecPubKey, "Failed to generate signed certificate")
68+
69+
// create our CA
70+
rootCA, err := ca.NewCA(caDir, testCA2Name)
71+
assert.NoError(t, err, "Error generating CA")
72+
73+
err = rootCA.SignCertificate(certDir, testName, ecPubKey)
74+
assert.NoError(t, err, "Failed to generate signed certificate")
75+
76+
// check to make sure the signed public key was stored
77+
pemFile := filepath.Join(certDir, testName+"-cert.pem")
78+
assert.Equal(t, true, checkForFile(pemFile),
79+
"Expected to find file "+pemFile)
80+
cleanup(testDir)
81+
82+
}
83+
84+
func cleanup(dir string) {
85+
os.RemoveAll(dir)
86+
}
87+
88+
func checkForFile(file string) bool {
89+
if _, err := os.Stat(file); os.IsNotExist(err) {
90+
return false
91+
}
92+
return true
93+
}
+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
Copyright IBM Corp. 2017 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+
package ca
17+
18+
import (
19+
"crypto"
20+
"crypto/ecdsa"
21+
"crypto/rand"
22+
"crypto/x509"
23+
"crypto/x509/pkix"
24+
"encoding/pem"
25+
"math/big"
26+
"os"
27+
"time"
28+
29+
"path/filepath"
30+
31+
"github.com/hyperledger/fabric/common/tools/cryptogen/csp"
32+
)
33+
34+
type CA struct {
35+
Name string
36+
//SignKey *ecdsa.PrivateKey
37+
Signer crypto.Signer
38+
SignCert *x509.Certificate
39+
}
40+
41+
// NewCA creates an instance of CA and saves the signing key pair in
42+
// baseDir/name
43+
func NewCA(baseDir, name string) (*CA, error) {
44+
45+
err := os.MkdirAll(baseDir, 0755)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
//key, err := genKeyECDSA(caDir, name)
51+
priv, signer, err := csp.GeneratePrivateKey(baseDir)
52+
// get public signing certificate
53+
ecPubKey, err := csp.GetECPublicKey(priv)
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
template, err := x509Template()
59+
60+
if err != nil {
61+
return nil, err
62+
}
63+
64+
//this is a CA
65+
template.IsCA = true
66+
template.KeyUsage |= x509.KeyUsageCertSign | x509.KeyUsageCRLSign
67+
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
68+
69+
//set the organization for the subject
70+
subject := subjectTemplate()
71+
subject.Organization = []string{name}
72+
subject.CommonName = name
73+
74+
template.Subject = subject
75+
template.SubjectKeyId = priv.SKI()
76+
77+
x509Cert, err := genCertificateECDSA(baseDir, name, &template, &template,
78+
ecPubKey, signer)
79+
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
ca := &CA{
85+
Name: name,
86+
Signer: signer,
87+
SignCert: x509Cert,
88+
}
89+
90+
return ca, nil
91+
}
92+
93+
// SignCertificate creates a signed certificate based on a built-in template
94+
// and saves it in baseDir/name
95+
func (ca *CA) SignCertificate(baseDir, name string, pub *ecdsa.PublicKey) error {
96+
97+
template, err := x509Template()
98+
99+
if err != nil {
100+
return err
101+
}
102+
103+
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
104+
105+
//set the organization for the subject
106+
subject := subjectTemplate()
107+
subject.CommonName = name
108+
109+
template.Subject = subject
110+
111+
_, err = genCertificateECDSA(baseDir, name, &template, ca.SignCert,
112+
pub, ca.Signer)
113+
114+
if err != nil {
115+
return err
116+
}
117+
118+
return nil
119+
}
120+
121+
// default template for X509 subject
122+
func subjectTemplate() pkix.Name {
123+
return pkix.Name{
124+
Country: []string{"US"},
125+
Locality: []string{"San Francisco"},
126+
Province: []string{"California"},
127+
}
128+
}
129+
130+
// default template for X509 certificates
131+
func x509Template() (x509.Certificate, error) {
132+
133+
//generate a serial number
134+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
135+
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
136+
if err != nil {
137+
return x509.Certificate{}, err
138+
}
139+
140+
now := time.Now()
141+
//basic template to use
142+
x509 := x509.Certificate{
143+
SerialNumber: serialNumber,
144+
NotBefore: now,
145+
NotAfter: now.Add(3650 * 24 * time.Hour), //~ten years
146+
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
147+
BasicConstraintsValid: true,
148+
}
149+
return x509, nil
150+
151+
}
152+
153+
// generate a signed X509 certficate using ECDSA
154+
func genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey,
155+
priv interface{}) (*x509.Certificate, error) {
156+
157+
//create the x509 public cert
158+
certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv)
159+
if err != nil {
160+
return nil, err
161+
}
162+
163+
//write cert out to file
164+
fileName := filepath.Join(baseDir, name+"-cert.pem")
165+
certFile, err := os.Create(fileName)
166+
if err != nil {
167+
return nil, err
168+
}
169+
//pem encode the cert
170+
err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
171+
certFile.Close()
172+
if err != nil {
173+
return nil, err
174+
}
175+
176+
x509Cert, err := x509.ParseCertificate(certBytes)
177+
if err != nil {
178+
return nil, err
179+
}
180+
return x509Cert, nil
181+
}

common/tools/cryptogen/csp/csp.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
Copyright IBM Corp. 2017 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+
package csp
17+
18+
import (
19+
"crypto"
20+
"crypto/ecdsa"
21+
"crypto/x509"
22+
23+
"github.com/hyperledger/fabric/bccsp"
24+
"github.com/hyperledger/fabric/bccsp/factory"
25+
"github.com/hyperledger/fabric/bccsp/signer"
26+
"github.com/hyperledger/fabric/bccsp/sw"
27+
)
28+
29+
// GeneratePrivateKey creates a private key and stores it in keystorePath
30+
func GeneratePrivateKey(keystorePath string) (bccsp.Key,
31+
crypto.Signer, error) {
32+
33+
csp := factory.GetDefault()
34+
35+
// generate a key
36+
priv, err := csp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true})
37+
if err != nil {
38+
return nil, nil, err
39+
}
40+
// write it to the keystore
41+
ks, err := sw.NewFileBasedKeyStore(nil, keystorePath, false)
42+
if err != nil {
43+
return nil, nil, err
44+
}
45+
err = ks.StoreKey(priv)
46+
if err != nil {
47+
return nil, nil, err
48+
}
49+
50+
// create a crypto.Signer
51+
signer := &signer.CryptoSigner{}
52+
err = signer.Init(csp, priv)
53+
if err != nil {
54+
return nil, nil, err
55+
}
56+
57+
return priv, signer, nil
58+
59+
}
60+
61+
func GetECPublicKey(priv bccsp.Key) (*ecdsa.PublicKey, error) {
62+
63+
// get the public key
64+
pubKey, err := priv.PublicKey()
65+
if err != nil {
66+
return nil, err
67+
}
68+
// marshal to bytes
69+
pubKeyBytes, err := pubKey.Bytes()
70+
if err != nil {
71+
return nil, err
72+
}
73+
// unmarshal using pkix
74+
ecPubKey, err := x509.ParsePKIXPublicKey(pubKeyBytes)
75+
if err != nil {
76+
return nil, err
77+
}
78+
return ecPubKey.(*ecdsa.PublicKey), nil
79+
}

0 commit comments

Comments
 (0)