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