// initialize loads the given PKCS#11 module (shared library) if it is not // already loaded. It's an error to load a PKCS#11 module multiple times, so we // maintain a map of loaded modules. Note that there is no facility yet to // unload a module ("finalize" in PKCS#11 parlance). In general, modules will // be unloaded at the end of the process. The only place where you are likely // to need to explicitly unload a module is if you fork your process after a // Key has already been created, and the child process also needs to use // that module. func initialize(modulePath string) (ctx, error) { modulesMu.Lock() defer modulesMu.Unlock() module, ok := modules[modulePath] if ok { return module, nil } newModule := ctx(pkcs11.New(modulePath)) if newModule == nil { return nil, fmt.Errorf("unable to load PKCS#11 module") } err := newModule.Initialize() if err != nil { return nil, err } modules[modulePath] = newModule return newModule, nil }
// New instantiates a new handle to a PKCS #11-backed key. func New(module, tokenLabel, pin, privLabel string, slotID int) (ps *PKCS11Key, err error) { // Set up a new pkcs11 object and initialize it p := pkcs11.New(module) if p == nil { err = errors.New("unable to load PKCS#11 module") return } if err = p.Initialize(); err != nil { return } // Initialize a partial key ps = &PKCS11Key{ module: p, slotID: slotID, tokenLabel: tokenLabel, pin: pin, } // Look up the private key session, err := ps.openSession() if err != nil { ps.Destroy() return } defer ps.closeSession(session) template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_LABEL, privLabel), } if err = p.FindObjectsInit(session, template); err != nil { ps.Destroy() return } objs, _, err := p.FindObjects(session, 2) if err != nil { ps.Destroy() return } if err = p.FindObjectsFinal(session); err != nil { ps.Destroy() return } if len(objs) == 0 { err = errors.New("private key not found") ps.Destroy() return } ps.privateKeyHandle = objs[0] // Populate the pubic key from the private key // TODO: Add support for non-RSA keys, switching on CKA_KEY_TYPE template = []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil), pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil), } attr, err := p.GetAttributeValue(session, ps.privateKeyHandle, template) if err != nil { ps.Destroy() return } n := big.NewInt(0) e := int(0) gotModulus, gotExponent := false, false for _, a := range attr { if a.Type == pkcs11.CKA_MODULUS { n.SetBytes(a.Value) gotModulus = true } else if a.Type == pkcs11.CKA_PUBLIC_EXPONENT { bigE := big.NewInt(0) bigE.SetBytes(a.Value) e = int(bigE.Int64()) gotExponent = true } } if !gotModulus || !gotExponent { ps.Destroy() return } ps.publicKey = rsa.PublicKey{ N: n, E: e, } return }