Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions cmd/cryptogen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,23 @@ type NodeTemplate struct {

type NodeSpec struct {
isAdmin bool
Hostname string `yaml:"Hostname"`
CommonName string `yaml:"CommonName"`
Country string `yaml:"Country"`
Province string `yaml:"Province"`
Locality string `yaml:"Locality"`
OrganizationalUnit string `yaml:"OrganizationalUnit"`
StreetAddress string `yaml:"StreetAddress"`
PostalCode string `yaml:"PostalCode"`
SANS []string `yaml:"SANS"`
PublicKeyAlgorithm string `yaml:"PublicKeyAlgorithm"`
Hostname string `yaml:"Hostname"`
CommonName string `yaml:"CommonName"`
Country string `yaml:"Country"`
Province string `yaml:"Province"`
Locality string `yaml:"Locality"`
OrganizationalUnit string `yaml:"OrganizationalUnit"`
StreetAddress string `yaml:"StreetAddress"`
PostalCode string `yaml:"PostalCode"`
SANS []string `yaml:"SANS"`
PublicKeyAlgorithm string `yaml:"PublicKeyAlgorithm"`
Attrs map[string]string `yaml:"Attrs"`
}

type UsersSpec struct {
Count int `yaml:"Count"`
PublicKeyAlgorithm string `yaml:"PublicKeyAlgorithm"`
Count int `yaml:"Count"`
PublicKeyAlgorithm string `yaml:"PublicKeyAlgorithm"`
Attrs map[string]string `yaml:"Attrs"`
}

type OrgSpec struct {
Expand Down Expand Up @@ -198,6 +200,8 @@ PeerOrgs:
Users:
Count: 1
PublicKeyAlgorithm: "ecdsa"
Attrs:
abac.creator: "true"

# ---------------------------------------------------------------------------
# Org2: See "Org1" for full specification
Expand Down Expand Up @@ -348,6 +352,7 @@ func extendPeerOrg(orgSpec OrgSpec) {
user := NodeSpec{
CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName),
PublicKeyAlgorithm: publicKeyAlg,
Attrs: orgSpec.Users.Attrs,
}

users = append(users, user)
Expand Down Expand Up @@ -567,6 +572,7 @@ func generatePeerOrg(baseDir string, orgSpec OrgSpec) {
user := NodeSpec{
CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName),
PublicKeyAlgorithm: publicKeyAlg,
Attrs: orgSpec.Users.Attrs,
}

users = append(users, user)
Expand Down Expand Up @@ -638,7 +644,7 @@ func generateNodes(baseDir string, nodes []NodeSpec, signCA *ca.CA, tlsCA *ca.CA
if node.isAdmin && nodeOUs {
currentNodeType = msp.ADMIN
}
err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, signCA, tlsCA, currentNodeType, nodeOUs, node.PublicKeyAlgorithm)
err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, signCA, tlsCA, currentNodeType, nodeOUs, node.PublicKeyAlgorithm, node.Attrs)
if err != nil {
fmt.Printf("Error generating local MSP for %v:\n%v\n", node, err)
os.Exit(1)
Expand Down
35 changes: 34 additions & 1 deletion internal/cryptogen/ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/json"
"encoding/pem"
"fmt"
"math/big"
Expand All @@ -26,6 +28,8 @@ import (
"github.com/pkg/errors"
)

var attrOID = asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6, 7, 8, 1}

type CA struct {
Name string
Country string
Expand Down Expand Up @@ -112,13 +116,37 @@ func NewCA(
return ca, err
}

// attrExtension mirrors the fabric-ca Attributes struct for JSON marshalling.
type attrExtension struct {
Attrs map[string]string `json:"attrs"`
}

func (ca *CA) addAttributesToCert(attrs map[string]string, cert *x509.Certificate) error {
if len(attrs) == 0 {
return nil
}
buf, err := json.Marshal(attrExtension{Attrs: attrs})
if err != nil {
return errors.Wrap(err, "Failed to marshal attributes")
}
ext := pkix.Extension{
Id: attrOID,
Critical: false,
Value: buf,
}
cert.ExtraExtensions = append(cert.ExtraExtensions, ext)
return nil
}

// SignCertificate creates a signed certificate based on a built-in template
// and saves it in baseDir/name
// and saves it in baseDir/name. attrs, if non-nil, are embedded as a custom
// X.509 extension (OID 1.2.3.4.5.6.7.8.1) using the same format as fabric-ca.
func (ca *CA) SignCertificate(
baseDir,
name string,
orgUnits,
alternateNames []string,
attrs map[string]string,
pub crypto.PublicKey,
ku x509.KeyUsage,
eku []x509.ExtKeyUsage,
Expand Down Expand Up @@ -151,6 +179,11 @@ func (ca *CA) SignCertificate(
}
}

err := ca.addAttributesToCert(attrs, &template)
if err != nil {
return nil, err
}

cert, err := genCertificate(
baseDir,
name,
Expand Down
34 changes: 30 additions & 4 deletions internal/cryptogen/ca/ca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ package ca_test
import (
"crypto/ecdsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/json"
"net"
"os"
"path/filepath"
Expand Down Expand Up @@ -68,6 +71,7 @@ func TestLoadCertificateECDSA(t *testing.T) {
testName3,
nil,
nil,
nil,
&priv.(*ecdsa.PrivateKey).PublicKey,
x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
[]x509.ExtKeyUsage{x509.ExtKeyUsageAny},
Expand Down Expand Up @@ -186,6 +190,7 @@ func TestGenerateSignCertificate(t *testing.T) {
testName,
nil,
nil,
nil,
&priv.PublicKey,
x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
[]x509.ExtKeyUsage{x509.ExtKeyUsageAny},
Expand All @@ -201,6 +206,7 @@ func TestGenerateSignCertificate(t *testing.T) {
testName,
nil,
nil,
nil,
&priv.PublicKey,
x509.KeyUsageDigitalSignature,
[]x509.ExtKeyUsage{},
Expand All @@ -210,15 +216,15 @@ func TestGenerateSignCertificate(t *testing.T) {

// make sure ous are correctly set
ous := []string{"TestOU", "PeerOU"}
cert, err = rootCA.SignCertificate(certDir, testName, ous, nil, &priv.PublicKey,
cert, err = rootCA.SignCertificate(certDir, testName, ous, nil, nil, &priv.PublicKey,
x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
require.NoError(t, err)
require.Contains(t, cert.Subject.OrganizationalUnit, ous[0])
require.Contains(t, cert.Subject.OrganizationalUnit, ous[1])

// make sure sans are correctly set
sans := []string{testName2, testName3, testIP}
cert, err = rootCA.SignCertificate(certDir, testName, nil, sans, &priv.PublicKey,
cert, err = rootCA.SignCertificate(certDir, testName, nil, sans, nil, &priv.PublicKey,
x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
require.NoError(t, err)
require.Contains(t, cert.DNSNames, testName2)
Expand All @@ -231,7 +237,7 @@ func TestGenerateSignCertificate(t *testing.T) {
require.Equal(t, true, checkForFile(pemFile),
"Expected to find file "+pemFile)

_, err = rootCA.SignCertificate(certDir, "empty/CA", nil, nil, &priv.PublicKey,
_, err = rootCA.SignCertificate(certDir, "empty/CA", nil, nil, nil, &priv.PublicKey,
x509.KeyUsageKeyEncipherment, []x509.ExtKeyUsage{x509.ExtKeyUsageAny})
require.Error(t, err, "Bad name should fail")

Expand All @@ -240,9 +246,29 @@ func TestGenerateSignCertificate(t *testing.T) {
Name: "badCA",
SignCert: &x509.Certificate{},
}
_, err = badCA.SignCertificate(certDir, testName, nil, nil, &ecdsa.PublicKey{},
_, err = badCA.SignCertificate(certDir, testName, nil, nil, nil, &ecdsa.PublicKey{},
x509.KeyUsageKeyEncipherment, []x509.ExtKeyUsage{x509.ExtKeyUsageAny})
require.Error(t, err, "Empty CA should not be able to sign")

// verify attributes are embedded as the fabric-ca extension
attrs := map[string]string{"abac.creator": "true", "org.role": "member"}
cert, err = rootCA.SignCertificate(certDir, testName, nil, nil, attrs, &priv.PublicKey,
x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
require.NoError(t, err)
attrOID := asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6, 7, 8, 1}
var attrExt *pkix.Extension
for i := range cert.Extensions {
if cert.Extensions[i].Id.Equal(attrOID) {
attrExt = &cert.Extensions[i]
break
}
}
require.NotNil(t, attrExt, "attribute extension should be present")
var attrData struct {
Attrs map[string]string `json:"attrs"`
}
require.NoError(t, json.Unmarshal(attrExt.Value, &attrData))
require.Equal(t, attrs, attrData.Attrs)
}

func checkForFile(file string) bool {
Expand Down
4 changes: 4 additions & 0 deletions internal/cryptogen/msp/msp.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func GenerateLocalMSP(
nodeType int,
nodeOUs bool,
keyAlg string,
attrs map[string]string,
) error {
// create folder structure
mspDir := filepath.Join(baseDir, "msp")
Expand Down Expand Up @@ -88,6 +89,7 @@ func GenerateLocalMSP(
name,
ous,
nil,
attrs,
getPublicKey(priv),
x509.KeyUsageDigitalSignature,
[]x509.ExtKeyUsage{},
Expand Down Expand Up @@ -150,6 +152,7 @@ func GenerateLocalMSP(
name,
nil,
sans,
nil,
getPublicKey(tlsPrivKey),
x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
[]x509.ExtKeyUsage{
Expand Down Expand Up @@ -242,6 +245,7 @@ func GenerateVerifyingMSP(
signCA.Name,
nil,
nil,
nil,
getPublicKey(priv),
x509.KeyUsageDigitalSignature,
[]x509.ExtKeyUsage{},
Expand Down
10 changes: 5 additions & 5 deletions internal/cryptogen/msp/msp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var testDir = filepath.Join(os.TempDir(), "msp-test")
func testGenerateLocalMSP(t *testing.T, nodeOUs bool) {
cleanup(testDir)

err := msp.GenerateLocalMSP(testDir, testName, nil, &ca.CA{}, &ca.CA{}, msp.PEER, nodeOUs, ECDSA)
err := msp.GenerateLocalMSP(testDir, testName, nil, &ca.CA{}, &ca.CA{}, msp.PEER, nodeOUs, ECDSA, nil)
require.Error(t, err, "Empty CA should have failed")

caDir := filepath.Join(testDir, "ca")
Expand Down Expand Up @@ -65,7 +65,7 @@ func testGenerateLocalMSP(t *testing.T, nodeOUs bool) {
require.Equal(t, testPostalCode, signCA.SignCert.Subject.PostalCode[0], "Failed to match postalCode")

// generate local MSP for nodeType=PEER
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.PEER, nodeOUs, ECDSA)
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.PEER, nodeOUs, ECDSA, nil)
require.NoError(t, err, "Failed to generate local MSP")

// check to see that the right files were generated/saved
Expand Down Expand Up @@ -97,7 +97,7 @@ func testGenerateLocalMSP(t *testing.T, nodeOUs bool) {
}

// generate local MSP for nodeType=CLIENT
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.CLIENT, nodeOUs, ECDSA)
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.CLIENT, nodeOUs, ECDSA, nil)
require.NoError(t, err, "Failed to generate local MSP")
// check all
for _, file := range mspFiles {
Expand All @@ -111,10 +111,10 @@ func testGenerateLocalMSP(t *testing.T, nodeOUs bool) {
}

tlsCA.Name = "test/fail"
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.CLIENT, nodeOUs, ECDSA)
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.CLIENT, nodeOUs, ECDSA, nil)
require.Error(t, err, "Should have failed with CA name 'test/fail'")
signCA.Name = "test/fail"
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.ORDERER, nodeOUs, ECDSA)
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.ORDERER, nodeOUs, ECDSA, nil)
require.Error(t, err, "Should have failed with CA name 'test/fail'")
t.Log(err)
cleanup(testDir)
Expand Down
Empty file added pr.md
Empty file.