forked from hyperledger/fabric
-
Notifications
You must be signed in to change notification settings - Fork 11
/
main.go
201 lines (166 loc) · 7.05 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package main
// idemixgen is a command line tool that generates the CA's keys and
// generates MSP configs for siging and for verification
// This tool can be used to setup the peers and CA to support
// the Identity Mixer MSP
import (
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/tools/idemixgen/idemixca"
"github.com/hyperledger/fabric/common/tools/idemixgen/metadata"
"github.com/hyperledger/fabric/idemix"
"github.com/hyperledger/fabric/msp"
"github.com/pkg/errors"
"gopkg.in/alecthomas/kingpin.v2"
)
const (
IdemixDirIssuer = "ca"
IdemixConfigIssuerSecretKey = "IssuerSecretKey"
IdemixConfigRevocationKey = "RevocationKey"
)
// command line flags
var (
app = kingpin.New("idemixgen", "Utility for generating key material to be used with the Identity Mixer MSP in Hyperledger Fabric")
outputDir = app.Flag("output", "The output directory in which to place artifacts").Default("idemix-config").String()
genIssuerKey = app.Command("ca-keygen", "Generate CA key material")
genSignerConfig = app.Command("signerconfig", "Generate a default signer for this Idemix MSP")
genCAInput = genSignerConfig.Flag("ca-input", "The folder where CA's secrets are stored").String()
genCredOU = genSignerConfig.Flag("org-unit", "The Organizational Unit of the default signer").Short('u').String()
genCredIsAdmin = genSignerConfig.Flag("admin", "Make the default signer admin").Short('a').Bool()
genCredEnrollmentId = genSignerConfig.Flag("enrollmentId", "The enrollment id of the default signer").Short('e').String()
genCredRevocationHandle = genSignerConfig.Flag("revocationHandle", "The handle used to revoke this signer").Short('r').Int()
version = app.Command("version", "Show version information")
)
func main() {
app.HelpFlag.Short('h')
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
case genIssuerKey.FullCommand():
isk, ipk, err := idemixca.GenerateIssuerKey()
handleError(err)
revocationKey, err := idemix.GenerateLongTermRevocationKey()
handleError(err)
encodedRevocationSK, err := x509.MarshalECPrivateKey(revocationKey)
handleError(err)
pemEncodedRevocationSK := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: encodedRevocationSK})
handleError(err)
encodedRevocationPK, err := x509.MarshalPKIXPublicKey(revocationKey.Public())
handleError(err)
pemEncodedRevocationPK := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: encodedRevocationPK})
// Prevent overwriting the existing key
path := filepath.Join(*outputDir, IdemixDirIssuer)
checkDirectoryNotExists(path, fmt.Sprintf("Directory %s already exists", path))
path = filepath.Join(*outputDir, msp.IdemixConfigDirMsp)
checkDirectoryNotExists(path, fmt.Sprintf("Directory %s already exists", path))
// write private and public keys to the file
handleError(os.MkdirAll(filepath.Join(*outputDir, IdemixDirIssuer), 0770))
handleError(os.MkdirAll(filepath.Join(*outputDir, msp.IdemixConfigDirMsp), 0770))
writeFile(filepath.Join(*outputDir, IdemixDirIssuer, IdemixConfigIssuerSecretKey), isk)
writeFile(filepath.Join(*outputDir, IdemixDirIssuer, IdemixConfigRevocationKey), pemEncodedRevocationSK)
writeFile(filepath.Join(*outputDir, IdemixDirIssuer, msp.IdemixConfigFileIssuerPublicKey), ipk)
writeFile(filepath.Join(*outputDir, msp.IdemixConfigDirMsp, msp.IdemixConfigFileRevocationPublicKey), pemEncodedRevocationPK)
writeFile(filepath.Join(*outputDir, msp.IdemixConfigDirMsp, msp.IdemixConfigFileIssuerPublicKey), ipk)
case genSignerConfig.FullCommand():
roleMask := 0
if *genCredIsAdmin {
roleMask = msp.GetRoleMaskFromIdemixRole(msp.ADMIN)
} else {
roleMask = msp.GetRoleMaskFromIdemixRole(msp.MEMBER)
}
if *genCAInput == "" {
genCAInput = outputDir
}
ipk, ipkRaw := readIssuerKey()
rsk := readRevocationKey()
rpk := readRevocationPublicKey()
config, err := idemixca.GenerateSignerConfig(
roleMask,
*genCredOU,
*genCredEnrollmentId,
*genCredRevocationHandle,
ipk, rsk,
)
handleError(err)
path := filepath.Join(*outputDir, msp.IdemixConfigDirUser)
checkDirectoryNotExists(path, fmt.Sprintf("This MSP config already contains a directory \"%s\"", path))
// Write config to file
handleError(os.MkdirAll(filepath.Join(*outputDir, msp.IdemixConfigDirUser), 0770))
writeFile(filepath.Join(*outputDir, msp.IdemixConfigDirUser, msp.IdemixConfigFileSigner), config)
// Write CA public info in case genCAInput != outputDir
if *genCAInput != *outputDir {
handleError(os.MkdirAll(filepath.Join(*outputDir, msp.IdemixConfigDirMsp), 0770))
writeFile(filepath.Join(*outputDir, msp.IdemixConfigDirMsp, msp.IdemixConfigFileRevocationPublicKey), rpk)
writeFile(filepath.Join(*outputDir, msp.IdemixConfigDirMsp, msp.IdemixConfigFileIssuerPublicKey), ipkRaw)
}
case version.FullCommand():
printVersion()
}
}
func printVersion() {
fmt.Println(metadata.GetVersionInfo())
}
// writeFile writes bytes to a file and panics in case of an error
func writeFile(path string, contents []byte) {
handleError(ioutil.WriteFile(path, contents, 0640))
}
// readIssuerKey reads the issuer key from the current directory
func readIssuerKey() (*idemix.IssuerKey, []byte) {
path := filepath.Join(*genCAInput, IdemixDirIssuer, IdemixConfigIssuerSecretKey)
isk, err := ioutil.ReadFile(path)
if err != nil {
handleError(errors.Wrapf(err, "failed to open issuer secret key file: %s", path))
}
path = filepath.Join(*genCAInput, IdemixDirIssuer, msp.IdemixConfigFileIssuerPublicKey)
ipkBytes, err := ioutil.ReadFile(path)
if err != nil {
handleError(errors.Wrapf(err, "failed to open issuer public key file: %s", path))
}
ipk := &idemix.IssuerPublicKey{}
handleError(proto.Unmarshal(ipkBytes, ipk))
key := &idemix.IssuerKey{Isk: isk, Ipk: ipk}
return key, ipkBytes
}
func readRevocationKey() *ecdsa.PrivateKey {
path := filepath.Join(*genCAInput, IdemixDirIssuer, IdemixConfigRevocationKey)
keyBytes, err := ioutil.ReadFile(path)
if err != nil {
handleError(errors.Wrapf(err, "failed to open revocation secret key file: %s", path))
}
block, _ := pem.Decode(keyBytes)
if block == nil {
handleError(errors.Errorf("failed to decode ECDSA private key"))
}
key, err := x509.ParseECPrivateKey(block.Bytes)
handleError(err)
return key
}
func readRevocationPublicKey() []byte {
path := filepath.Join(*genCAInput, msp.IdemixConfigDirMsp, msp.IdemixConfigFileRevocationPublicKey)
keyBytes, err := ioutil.ReadFile(path)
if err != nil {
handleError(errors.Wrapf(err, "failed to open revocation secret key file: %s", path))
}
return keyBytes
}
// checkDirectoryNotExists checks whether a directory with the given path already exists and exits if this is the case
func checkDirectoryNotExists(path string, errorMessage string) {
_, err := os.Stat(path)
if err == nil {
handleError(errors.New(errorMessage))
}
}
func handleError(err error) {
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}