github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/integration/pkcs11/pkcs11_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package pkcs11 8 9 import ( 10 "crypto/ecdsa" 11 "crypto/elliptic" 12 "crypto/rand" 13 "crypto/sha256" 14 "crypto/x509" 15 "crypto/x509/pkix" 16 "encoding/asn1" 17 "encoding/hex" 18 "encoding/pem" 19 "fmt" 20 "io/ioutil" 21 "math/big" 22 "os" 23 "path/filepath" 24 "syscall" 25 "time" 26 27 bpkcs11 "github.com/osdi23p228/fabric/bccsp/pkcs11" 28 "github.com/osdi23p228/fabric/integration/nwo" 29 "github.com/osdi23p228/fabric/integration/nwo/fabricconfig" 30 "github.com/miekg/pkcs11" 31 . "github.com/onsi/ginkgo" 32 . "github.com/onsi/gomega" 33 "github.com/tedsuo/ifrit" 34 ) 35 36 var _ = Describe("PKCS11 enabled network", func() { 37 var ( 38 tempDir string 39 network *nwo.Network 40 process ifrit.Process 41 ) 42 43 BeforeEach(func() { 44 var err error 45 tempDir, err = ioutil.TempDir("", "p11") 46 Expect(err).NotTo(HaveOccurred()) 47 48 network = nwo.New(nwo.BasicSolo(), tempDir, nil, StartPort(), components) 49 network.GenerateConfigTree() 50 network.Bootstrap() 51 52 By("configuring PKCS11 artifacts") 53 setupPKCS11(network) 54 55 By("starting fabric processes") 56 networkRunner := network.NetworkGroupRunner() 57 process = ifrit.Invoke(networkRunner) 58 Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed()) 59 }) 60 61 AfterEach(func() { 62 if process != nil { 63 process.Signal(syscall.SIGTERM) 64 Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive()) 65 } 66 network.Cleanup() 67 os.RemoveAll(tempDir) 68 }) 69 70 It("executes transactions against a basic solo network", func() { 71 chaincode := nwo.Chaincode{ 72 Name: "mycc", 73 Version: "0.0", 74 Path: components.Build("github.com/osdi23p228/fabric/integration/chaincode/simple/cmd"), 75 Lang: "binary", 76 PackageFile: filepath.Join(tempDir, "simplecc.tar.gz"), 77 Ctor: `{"Args":["init","a","100","b","200"]}`, 78 SignaturePolicy: `AND ('Org1MSP.member','Org2MSP.member')`, 79 Sequence: "1", 80 InitRequired: true, 81 Label: "my_prebuilt_chaincode", 82 } 83 84 orderer := network.Orderer("orderer") 85 network.CreateAndJoinChannels(orderer) 86 87 nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.PeersWithChannel("testchannel")...) 88 nwo.DeployChaincode(network, "testchannel", orderer, chaincode) 89 runQueryInvokeQuery(network, orderer, network.Peer("Org1", "peer0"), "testchannel") 90 }) 91 }) 92 93 func setupPKCS11(network *nwo.Network) { 94 lib, pin, label := bpkcs11.FindPKCS11Lib() 95 96 By("establishing a PKCS11 session") 97 ctx, sess := setupPKCS11Ctx(lib, label, pin) 98 defer ctx.Destroy() 99 defer ctx.CloseSession(sess) 100 101 configurePeerPKCS11(ctx, sess, network) 102 configureOrdererPKCS11(ctx, sess, network) 103 104 bccspConfig := &fabricconfig.BCCSP{ 105 Default: "PKCS11", 106 PKCS11: &fabricconfig.PKCS11{ 107 Security: 256, 108 Hash: "SHA2", 109 Pin: pin, 110 Label: label, 111 Library: lib, 112 }, 113 } 114 115 By("updating bccsp peer config") 116 for _, peer := range network.Peers { 117 peerConfig := network.ReadPeerConfig(peer) 118 peerConfig.Peer.BCCSP = bccspConfig 119 network.WritePeerConfig(peer, peerConfig) 120 } 121 122 By("updating bccsp orderer config") 123 orderer := network.Orderer("orderer") 124 ordererConfig := network.ReadOrdererConfig(orderer) 125 ordererConfig.General.BCCSP = bccspConfig 126 network.WriteOrdererConfig(orderer, ordererConfig) 127 } 128 129 func configurePeerPKCS11(ctx *pkcs11.Ctx, sess pkcs11.SessionHandle, network *nwo.Network) { 130 for _, peer := range network.Peers { 131 orgName := peer.Organization 132 133 peerPubKey, peerCSR, peerSerial := createCSR(ctx, sess, orgName, "peer") 134 adminPubKey, adminCSR, adminSerial := createCSR(ctx, sess, orgName, "admin") 135 userPubKey, userCSR, userSerial := createCSR(ctx, sess, orgName, "client") 136 137 domain := network.Organization(orgName).Domain 138 139 // Retrieves org CA cert 140 orgCAPath := network.PeerOrgCADir(network.Organization(orgName)) 141 caBytes, err := ioutil.ReadFile(filepath.Join(orgCAPath, fmt.Sprintf("ca.%s-cert.pem", domain))) 142 Expect(err).NotTo(HaveOccurred()) 143 144 By("Updating the peer signcerts") 145 newOrdererPemCert := buildCert(caBytes, orgCAPath, peerCSR, peerSerial, peerPubKey) 146 updateMSPFolder(network.PeerLocalMSPDir(peer), fmt.Sprintf("peer.%s-cert.pem", domain), newOrdererPemCert) 147 148 By("Updating the peer admin user signcerts") 149 newAdminPemCert := buildCert(caBytes, orgCAPath, adminCSR, adminSerial, adminPubKey) 150 orgAdminMSPPath := network.PeerUserMSPDir(peer, "Admin") 151 updateMSPFolder(orgAdminMSPPath, fmt.Sprintf("Admin@%s-cert.pem", domain), newAdminPemCert) 152 153 By("Updating the peer user1 signcerts") 154 newUserPemCert := buildCert(caBytes, orgCAPath, userCSR, userSerial, userPubKey) 155 orgUserMSPPath := network.PeerUserMSPDir(peer, "User1") 156 updateMSPFolder(orgUserMSPPath, fmt.Sprintf("User1@%s-cert.pem", domain), newUserPemCert) 157 } 158 } 159 160 func configureOrdererPKCS11(ctx *pkcs11.Ctx, sess pkcs11.SessionHandle, network *nwo.Network) { 161 orderer := network.Orderer("orderer") 162 orgName := orderer.Organization 163 domain := network.Organization(orgName).Domain 164 165 ordererPubKey, ordererCSR, ordererSerial := createCSR(ctx, sess, orgName, "orderer") 166 adminPubKey, adminCSR, adminSerial := createCSR(ctx, sess, orgName, "admin") 167 168 // Retrieves org CA cert 169 orgCAPath := network.OrdererOrgCADir(network.Organization(orgName)) 170 caBytes, err := ioutil.ReadFile(filepath.Join(orgCAPath, fmt.Sprintf("ca.%s-cert.pem", domain))) 171 Expect(err).NotTo(HaveOccurred()) 172 173 By("Updating the orderer signcerts") 174 newOrdererPemCert := buildCert(caBytes, orgCAPath, ordererCSR, ordererSerial, ordererPubKey) 175 updateMSPFolder(network.OrdererLocalMSPDir(orderer), fmt.Sprintf("orderer.%s-cert.pem", domain), newOrdererPemCert) 176 177 By("Updating the orderer admin user signcerts") 178 newAdminPemCert := buildCert(caBytes, orgCAPath, adminCSR, adminSerial, adminPubKey) 179 orgAdminMSPPath := network.OrdererUserMSPDir(orderer, "Admin") 180 updateMSPFolder(orgAdminMSPPath, fmt.Sprintf("Admin@%s-cert.pem", domain), newAdminPemCert) 181 } 182 183 // Creates pkcs11 context and session 184 func setupPKCS11Ctx(lib, label, pin string) (*pkcs11.Ctx, pkcs11.SessionHandle) { 185 ctx := pkcs11.New(lib) 186 187 err := ctx.Initialize() 188 Expect(err).NotTo(HaveOccurred()) 189 190 slot := findPKCS11Slot(ctx, label) 191 Expect(slot).Should(BeNumerically(">", 0), "Could not find slot with label %s", label) 192 193 sess, err := ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) 194 Expect(err).NotTo(HaveOccurred()) 195 196 // Login 197 err = ctx.Login(sess, pkcs11.CKU_USER, pin) 198 Expect(err).NotTo(HaveOccurred()) 199 200 return ctx, sess 201 } 202 203 // Identifies pkcs11 slot using specified label 204 func findPKCS11Slot(ctx *pkcs11.Ctx, label string) uint { 205 slots, err := ctx.GetSlotList(true) 206 Expect(err).NotTo(HaveOccurred()) 207 208 for _, s := range slots { 209 tokInfo, err := ctx.GetTokenInfo(s) 210 Expect(err).NotTo(HaveOccurred()) 211 212 if tokInfo.Label == label { 213 return s 214 } 215 } 216 217 return 0 218 } 219 220 // Creates CSR for provided organization and organizational unit 221 func createCSR(ctx *pkcs11.Ctx, sess pkcs11.SessionHandle, org, ou string) (*ecdsa.PublicKey, *x509.CertificateRequest, *big.Int) { 222 pubKey, pkcs11Key := generateKeyPair(ctx, sess) 223 224 csrTemplate := x509.CertificateRequest{ 225 Subject: pkix.Name{ 226 Country: []string{"US"}, 227 Province: []string{"California"}, 228 Locality: []string{"San Francisco"}, 229 Organization: []string{fmt.Sprintf("%s.example.com", org)}, 230 OrganizationalUnit: []string{ou}, 231 CommonName: fmt.Sprintf("peer.%s.example.com", org), 232 }, 233 SignatureAlgorithm: x509.ECDSAWithSHA256, 234 } 235 236 csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, pkcs11Key) 237 Expect(err).NotTo(HaveOccurred()) 238 239 csr, err := x509.ParseCertificateRequest(csrBytes) 240 Expect(err).NotTo(HaveOccurred()) 241 err = csr.CheckSignature() 242 Expect(err).NotTo(HaveOccurred()) 243 244 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 245 serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 246 Expect(err).NotTo(HaveOccurred()) 247 248 return pubKey, csr, serialNumber 249 } 250 251 func buildCert(caBytes []byte, org1CAPath string, csr *x509.CertificateRequest, serialNumber *big.Int, pubKey *ecdsa.PublicKey) []byte { 252 pemBlock, _ := pem.Decode(caBytes) 253 Expect(pemBlock).NotTo(BeNil()) 254 255 caCert, err := x509.ParseCertificate(pemBlock.Bytes) 256 Expect(err).NotTo(HaveOccurred()) 257 258 keyBytes, err := ioutil.ReadFile(filepath.Join(org1CAPath, "priv_sk")) 259 Expect(err).NotTo(HaveOccurred()) 260 261 pemBlock, _ = pem.Decode(keyBytes) 262 Expect(pemBlock).NotTo(BeNil()) 263 key, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes) 264 Expect(err).NotTo(HaveOccurred()) 265 caKey := key.(*ecdsa.PrivateKey) 266 267 certTemplate := &x509.Certificate{ 268 Signature: csr.Signature, 269 SignatureAlgorithm: csr.SignatureAlgorithm, 270 PublicKey: csr.PublicKey, 271 PublicKeyAlgorithm: csr.PublicKeyAlgorithm, 272 273 SerialNumber: serialNumber, 274 NotBefore: time.Now().Add(-1 * time.Minute).UTC(), 275 NotAfter: time.Now().Add(365 * 24 * time.Hour).UTC(), 276 BasicConstraintsValid: true, 277 278 Subject: csr.Subject, 279 KeyUsage: x509.KeyUsageDigitalSignature, 280 ExtKeyUsage: []x509.ExtKeyUsage{}, 281 } 282 283 // Use root CA to create and sign cert 284 signedCert, err := x509.CreateCertificate(rand.Reader, certTemplate, caCert, pubKey, caKey) 285 Expect(err).NotTo(HaveOccurred()) 286 287 return pem.EncodeToMemory(&pem.Block{Bytes: signedCert, Type: "CERTIFICATE"}) 288 } 289 290 // Overwrites existing cert and removes private key from keystore folder 291 func updateMSPFolder(path, certName string, cert []byte) { 292 // Overwrite existing certificate with new certificate 293 err := ioutil.WriteFile(filepath.Join(path, "signcerts", certName), cert, 0644) 294 Expect(err).NotTo(HaveOccurred()) 295 296 // delete the existing private key - this is stored in the hsm 297 adminKSCert := filepath.Join(path, "keystore", "priv_sk") 298 err = os.Remove(adminKSCert) 299 Expect(err).NotTo(HaveOccurred()) 300 } 301 302 // Generating key pair in HSM, convert, and return keys 303 func generateKeyPair(ctx *pkcs11.Ctx, sess pkcs11.SessionHandle) (*ecdsa.PublicKey, *P11ECDSAKey) { 304 publabel, privlabel := "BCPUB7", "BCPRV7" 305 306 curve := asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} // secp256r1 Curve 307 308 marshaledOID, err := asn1.Marshal(curve) 309 Expect(err).NotTo(HaveOccurred()) 310 311 pubAttrs := []*pkcs11.Attribute{ 312 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), 313 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), 314 pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), 315 pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), 316 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), 317 318 pkcs11.NewAttribute(pkcs11.CKA_ID, publabel), 319 pkcs11.NewAttribute(pkcs11.CKA_LABEL, publabel), 320 } 321 322 privAttrs := []*pkcs11.Attribute{ 323 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), 324 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), 325 pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), 326 pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), 327 328 pkcs11.NewAttribute(pkcs11.CKA_ID, privlabel), 329 pkcs11.NewAttribute(pkcs11.CKA_LABEL, privlabel), 330 331 pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false), 332 pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true), 333 } 334 335 pubK, privK, err := ctx.GenerateKeyPair( 336 sess, 337 []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_EC_KEY_PAIR_GEN, nil)}, 338 pubAttrs, 339 privAttrs, 340 ) 341 Expect(err).NotTo(HaveOccurred()) 342 343 ecpt := ecPoint(ctx, sess, pubK) 344 Expect(ecpt).NotTo(BeEmpty(), "CKA_EC_POINT not found") 345 346 hash := sha256.Sum256(ecpt) 347 ski := hash[:] 348 349 setskiT := []*pkcs11.Attribute{ 350 pkcs11.NewAttribute(pkcs11.CKA_ID, ski), 351 pkcs11.NewAttribute(pkcs11.CKA_LABEL, hex.EncodeToString(ski)), 352 } 353 354 err = ctx.SetAttributeValue(sess, pubK, setskiT) 355 Expect(err).NotTo(HaveOccurred()) 356 357 err = ctx.SetAttributeValue(sess, privK, setskiT) 358 Expect(err).NotTo(HaveOccurred()) 359 360 // convert pub key to rsa types 361 nistCurve := elliptic.P256() 362 x, y := elliptic.Unmarshal(nistCurve, ecpt) 363 if x == nil { 364 Expect(x).NotTo(BeNil(), "Failed Unmarshaling Public Key") 365 } 366 367 pubKey := &ecdsa.PublicKey{Curve: nistCurve, X: x, Y: y} 368 369 pkcs11Key := &P11ECDSAKey{ 370 ctx: ctx, 371 session: sess, 372 publicKey: pubKey, 373 privateKeyHandle: privK, 374 } 375 376 return pubKey, pkcs11Key 377 } 378 379 // SoftHSM reports extra two bytes before the uncompressed point 380 // see /bccsp/pkcs11/pkcs11.go::ecPoint() for additional details 381 func ecPoint(pkcs11lib *pkcs11.Ctx, session pkcs11.SessionHandle, key pkcs11.ObjectHandle) (ecpt []byte) { 382 template := []*pkcs11.Attribute{ 383 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil), 384 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil), 385 } 386 387 attr, err := pkcs11lib.GetAttributeValue(session, key, template) 388 if err != nil { 389 Expect(err).NotTo(HaveOccurred(), "PKCS11: get(EC point)") 390 } 391 392 for _, a := range attr { 393 if a.Type != pkcs11.CKA_EC_POINT { 394 continue 395 } 396 397 switch { 398 case ((len(a.Value) % 2) == 0) && (byte(0x04) == a.Value[0]) && (byte(0x04) == a.Value[len(a.Value)-1]): 399 ecpt = a.Value[0 : len(a.Value)-1] // Trim trailing 0x04 400 case byte(0x04) == a.Value[0] && byte(0x04) == a.Value[2]: 401 ecpt = a.Value[2:len(a.Value)] 402 default: 403 ecpt = a.Value 404 } 405 } 406 407 return ecpt 408 }