// Get the public key matching a private key // TODO: Add support for non-RSA keys, switching on CKA_KEY_TYPE func getPublicKey(module *pkcs11.Ctx, session pkcs11.SessionHandle, privateKeyHandle pkcs11.ObjectHandle) (rsa.PublicKey, error) { var noKey rsa.PublicKey template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil), pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil), } attr, err := module.GetAttributeValue(session, privateKeyHandle, template) if err != nil { return noKey, err } 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 { return noKey, errors.New("public key missing either modulus or exponent") } return rsa.PublicKey{ N: n, E: e, }, nil }
func listObjects(ctx IPKCS11Ctx, session pkcs11.SessionHandle) ([]pkcs11.ObjectHandle, error) { findTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE), } if err := ctx.FindObjectsInit(session, findTemplate); err != nil { logrus.Debugf("Failed to init: %s", err.Error()) return nil, err } objs, b, err := ctx.FindObjects(session, numSlots) for err == nil { var o []pkcs11.ObjectHandle o, b, err = ctx.FindObjects(session, numSlots) if err != nil { continue } if len(o) == 0 { break } objs = append(objs, o...) } if err != nil { logrus.Debugf("Failed to find: %s %v", err.Error(), b) if len(objs) == 0 { return nil, err } } if err := ctx.FindObjectsFinal(session); err != nil { logrus.Debugf("Failed to finalize: %s", err.Error()) return nil, err } return objs, nil }
// Sign returns a signature for a given signature request func sign(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte, passRetriever passphrase.Retriever, payload []byte) ([]byte, error) { err := login(ctx, session, passRetriever, pkcs11.CKU_USER, USER_PIN) if err != nil { return nil, fmt.Errorf("error logging in: %v", err) } defer ctx.Logout(session) // Define the ECDSA Private key template class := pkcs11.CKO_PRIVATE_KEY privateKeyTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, class), pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_ECDSA), pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID), } if err := ctx.FindObjectsInit(session, privateKeyTemplate); err != nil { logrus.Debugf("Failed to init find objects: %s", err.Error()) return nil, err } obj, _, err := ctx.FindObjects(session, 1) if err != nil { logrus.Debugf("Failed to find objects: %v", err) return nil, err } if err = ctx.FindObjectsFinal(session); err != nil { logrus.Debugf("Failed to finalize find objects: %s", err.Error()) return nil, err } if len(obj) != 1 { return nil, errors.New("length of objects found not 1") } var sig []byte err = ctx.SignInit( session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, obj[0]) if err != nil { return nil, err } // Get the SHA256 of the payload digest := sha256.Sum256(payload) if (yubikeyKeymode & KeymodeTouch) > 0 { touchToSignUI() defer touchDoneCallback() } // a call to Sign, whether or not Sign fails, will clear the SignInit sig, err = ctx.Sign(session, digest[:]) if err != nil { logrus.Debugf("Error while signing: %s", err) return nil, err } if sig == nil { return nil, errors.New("Failed to create signature") } return sig[:], nil }
func (ps *Key) getPrivateKey(module ctx, session pkcs11.SessionHandle, label string) (pkcs11.ObjectHandle, error) { var noHandle pkcs11.ObjectHandle template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_LABEL, label), } if err := module.FindObjectsInit(session, template); err != nil { return noHandle, err } objs, _, err := module.FindObjects(session, 2) if err != nil { return noHandle, err } if err = module.FindObjectsFinal(session); err != nil { return noHandle, err } if len(objs) == 0 { return noHandle, fmt.Errorf("private key not found") } privateKeyHandle := objs[0] // Check whether the key has the CKA_ALWAYS_AUTHENTICATE attribute. // If so, fail: we don't want to have to re-authenticate for each sign // operation. attributes, err := module.GetAttributeValue(session, privateKeyHandle, []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_ALWAYS_AUTHENTICATE, false), }) // The PKCS#11 spec states that C_GetAttributeValue may return // CKR_ATTRIBUTE_TYPE_INVALID if an object simply does not posses a given // attribute. We don't consider that an error: the absence of the // CKR_ATTRIBUTE_TYPE_INVALID property is just fine. if err != nil && err == pkcs11.Error(pkcs11.CKR_ATTRIBUTE_TYPE_INVALID) { return privateKeyHandle, nil } else if err != nil { return noHandle, err } for _, attribute := range attributes { if len(attribute.Value) > 0 && attribute.Value[0] == 1 { ps.alwaysAuthenticate = true } } return privateKeyHandle, nil }
func yubiRemoveKey(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte, passRetriever passphrase.Retriever, keyID string) error { err := login(ctx, session, passRetriever, pkcs11.CKU_SO, SO_USER_PIN) if err != nil { return err } defer ctx.Logout(session) template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID), //pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE), } if err := ctx.FindObjectsInit(session, template); err != nil { logrus.Debugf("Failed to init find objects: %s", err.Error()) return err } obj, b, err := ctx.FindObjects(session, 1) if err != nil { logrus.Debugf("Failed to find objects: %s %v", err.Error(), b) return err } if err := ctx.FindObjectsFinal(session); err != nil { logrus.Debugf("Failed to finalize find objects: %s", err.Error()) return err } if len(obj) != 1 { logrus.Debugf("should have found exactly one object") return err } // Delete the certificate err = ctx.DestroyObject(session, obj[0]) if err != nil { logrus.Debugf("Failed to delete cert") return err } return nil }
func (ps *Key) getPrivateKey(module *pkcs11.Ctx, session pkcs11.SessionHandle, label string) (pkcs11.ObjectHandle, error) { var noHandle pkcs11.ObjectHandle template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_LABEL, label), } if err := module.FindObjectsInit(session, template); err != nil { return noHandle, err } objs, _, err := module.FindObjects(session, 2) if err != nil { return noHandle, err } if err = module.FindObjectsFinal(session); err != nil { return noHandle, err } if len(objs) == 0 { return noHandle, fmt.Errorf("private key not found") } privateKeyHandle := objs[0] // Check whether the key has the CKA_ALWAYS_AUTHENTICATE attribute. // If so, fail: we don't want to have to re-authenticate for each sign // operation. attributes, err := module.GetAttributeValue(session, privateKeyHandle, []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_ALWAYS_AUTHENTICATE, false), }) if err != nil { return noHandle, err } for _, attribute := range attributes { if len(attribute.Value) > 0 && attribute.Value[0] == 1 { ps.alwaysAuthenticate = true } } return privateKeyHandle, nil }
func getPrivateKey(context *pkcs11.Ctx, session pkcs11.SessionHandle, label string) (pkcs11.ObjectHandle, error) { var noKey pkcs11.ObjectHandle template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_LABEL, label), } if err := context.FindObjectsInit(session, template); err != nil { return noKey, err } objs, _, err := context.FindObjects(session, 2) if err != nil { return noKey, err } if err = context.FindObjectsFinal(session); err != nil { return noKey, err } if len(objs) == 0 { err = fmt.Errorf("private key not found") return noKey, err } return objs[0], nil }
func getECDSAKey(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte) (*data.ECDSAPublicKey, string, error) { findTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID), pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), } attrTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0}), pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{0}), pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{0}), } if err := ctx.FindObjectsInit(session, findTemplate); err != nil { logrus.Debugf("Failed to init: %s", err.Error()) return nil, "", err } obj, _, err := ctx.FindObjects(session, 1) if err != nil { logrus.Debugf("Failed to find objects: %v", err) return nil, "", err } if err := ctx.FindObjectsFinal(session); err != nil { logrus.Debugf("Failed to finalize: %s", err.Error()) return nil, "", err } if len(obj) != 1 { logrus.Debugf("should have found one object") return nil, "", errors.New("no matching keys found inside of yubikey") } // Retrieve the public-key material to be able to create a new ECSAKey attr, err := ctx.GetAttributeValue(session, obj[0], attrTemplate) if err != nil { logrus.Debugf("Failed to get Attribute for: %v", obj[0]) return nil, "", err } // Iterate through all the attributes of this key and saves CKA_PUBLIC_EXPONENT and CKA_MODULUS. Removes ordering specific issues. var rawPubKey []byte for _, a := range attr { if a.Type == pkcs11.CKA_EC_POINT { rawPubKey = a.Value } } ecdsaPubKey := ecdsa.PublicKey{Curve: elliptic.P256(), X: new(big.Int).SetBytes(rawPubKey[3:35]), Y: new(big.Int).SetBytes(rawPubKey[35:])} pubBytes, err := x509.MarshalPKIXPublicKey(&ecdsaPubKey) if err != nil { logrus.Debugf("Failed to Marshal public key") return nil, "", err } return data.NewECDSAPublicKey(pubBytes), data.CanonicalRootRole, nil }
func getKeyType(module ctx, session pkcs11.SessionHandle, privateKeyHandle pkcs11.ObjectHandle) (c byte, err error) { attributes, err := module.GetAttributeValue(session, privateKeyHandle, []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, false), }) if err != nil { return } if (len(attributes) > 0) && (len(attributes[0].Value) > 0) { c = attributes[0].Value[0] } else { err = fmt.Errorf("No key type") } return }
// New instantiates a new handle to a PKCS #11-backed key. func New(module, slot, pin, privLabel string) (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, slotDescription: slot, 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 }
func getNextEmptySlot(ctx IPKCS11Ctx, session pkcs11.SessionHandle) ([]byte, error) { findTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), } attrTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_ID, []byte{0}), } if err := ctx.FindObjectsInit(session, findTemplate); err != nil { logrus.Debugf("Failed to init: %s", err.Error()) return nil, err } objs, b, err := ctx.FindObjects(session, numSlots) // if there are more objects than `numSlots`, get all of them until // there are no more to get for err == nil { var o []pkcs11.ObjectHandle o, b, err = ctx.FindObjects(session, numSlots) if err != nil { continue } if len(o) == 0 { break } objs = append(objs, o...) } taken := make(map[int]bool) if err != nil { logrus.Debugf("Failed to find: %s %v", err.Error(), b) return nil, err } if err = ctx.FindObjectsFinal(session); err != nil { logrus.Debugf("Failed to finalize: %s\n", err.Error()) return nil, err } for _, obj := range objs { // Retrieve the slot ID attr, err := ctx.GetAttributeValue(session, obj, attrTemplate) if err != nil { continue } // Iterate through attributes. If an ID attr was found, mark it as taken for _, a := range attr { if a.Type == pkcs11.CKA_ID { if len(a.Value) < 1 { continue } // a byte will always be capable of representing all slot IDs // for the Yubikeys slotNum := int(a.Value[0]) if slotNum >= numSlots { // defensive continue } taken[slotNum] = true } } } // iterate the token locations in our preferred order and use the first // available one. Otherwise exit the loop and return an error. for _, loc := range slotIDs { if !taken[loc] { return []byte{byte(loc)}, nil } } return nil, errors.New("Yubikey has no available slots.") }
func yubiListKeys(ctx IPKCS11Ctx, session pkcs11.SessionHandle) (keys map[string]yubiSlot, err error) { keys = make(map[string]yubiSlot) findTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), //pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID), pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE), } attrTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_ID, []byte{0}), pkcs11.NewAttribute(pkcs11.CKA_VALUE, []byte{0}), } if err = ctx.FindObjectsInit(session, findTemplate); err != nil { logrus.Debugf("Failed to init: %s", err.Error()) return } objs, b, err := ctx.FindObjects(session, numSlots) for err == nil { var o []pkcs11.ObjectHandle o, b, err = ctx.FindObjects(session, numSlots) if err != nil { continue } if len(o) == 0 { break } objs = append(objs, o...) } if err != nil { logrus.Debugf("Failed to find: %s %v", err.Error(), b) if len(objs) == 0 { return nil, err } } if err = ctx.FindObjectsFinal(session); err != nil { logrus.Debugf("Failed to finalize: %s", err.Error()) return } if len(objs) == 0 { return nil, errors.New("No keys found in yubikey.") } logrus.Debugf("Found %d objects matching list filters", len(objs)) for _, obj := range objs { var ( cert *x509.Certificate slot []byte ) // Retrieve the public-key material to be able to create a new ECDSA attr, err := ctx.GetAttributeValue(session, obj, attrTemplate) if err != nil { logrus.Debugf("Failed to get Attribute for: %v", obj) continue } // Iterate through all the attributes of this key and saves CKA_PUBLIC_EXPONENT and CKA_MODULUS. Removes ordering specific issues. for _, a := range attr { if a.Type == pkcs11.CKA_ID { slot = a.Value } if a.Type == pkcs11.CKA_VALUE { cert, err = x509.ParseCertificate(a.Value) if err != nil { continue } if !data.ValidRole(cert.Subject.CommonName) { continue } } } // we found nothing if cert == nil { continue } var ecdsaPubKey *ecdsa.PublicKey switch cert.PublicKeyAlgorithm { case x509.ECDSA: ecdsaPubKey = cert.PublicKey.(*ecdsa.PublicKey) default: logrus.Infof("Unsupported x509 PublicKeyAlgorithm: %d", cert.PublicKeyAlgorithm) continue } pubBytes, err := x509.MarshalPKIXPublicKey(ecdsaPubKey) if err != nil { logrus.Debugf("Failed to Marshal public key") continue } keys[data.NewECDSAPublicKey(pubBytes).ID()] = yubiSlot{ role: cert.Subject.CommonName, slotID: slot, } } return }
// addECDSAKey adds a key to the yubikey func addECDSAKey( ctx IPKCS11Ctx, session pkcs11.SessionHandle, privKey data.PrivateKey, pkcs11KeyID []byte, passRetriever passphrase.Retriever, role string, ) error { logrus.Debugf("Attempting to add key to yubikey with ID: %s", privKey.ID()) err := login(ctx, session, passRetriever, pkcs11.CKU_SO, SO_USER_PIN) if err != nil { return err } defer ctx.Logout(session) // Create an ecdsa.PrivateKey out of the private key bytes ecdsaPrivKey, err := x509.ParseECPrivateKey(privKey.Private()) if err != nil { return err } ecdsaPrivKeyD := ensurePrivateKeySize(ecdsaPrivKey.D.Bytes()) // Hard-coded policy: the generated certificate expires in 10 years. startTime := time.Now() template, err := trustmanager.NewCertificate(role, startTime, startTime.AddDate(10, 0, 0)) if err != nil { return fmt.Errorf("failed to create the certificate template: %v", err) } certBytes, err := x509.CreateCertificate(rand.Reader, template, template, ecdsaPrivKey.Public(), ecdsaPrivKey) if err != nil { return fmt.Errorf("failed to create the certificate: %v", err) } certTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE), pkcs11.NewAttribute(pkcs11.CKA_VALUE, certBytes), pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID), } privateKeyTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_ECDSA), pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID), pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}), pkcs11.NewAttribute(pkcs11.CKA_VALUE, ecdsaPrivKeyD), pkcs11.NewAttribute(pkcs11.CKA_VENDOR_DEFINED, yubikeyKeymode), } _, err = ctx.CreateObject(session, certTemplate) if err != nil { return fmt.Errorf("error importing: %v", err) } _, err = ctx.CreateObject(session, privateKeyTemplate) if err != nil { return fmt.Errorf("error importing: %v", err) } return nil }
// Create creates a key and returns its public components func (s *RSAHardwareCryptoService) Create(role, algo string) (data.PublicKey, error) { // For now generate random labels for keys // (diogo): add link between keyID and label in database so we can support multiple keys randomLabel := make([]byte, 32) _, err := rand.Read(randomLabel) if err != nil { return nil, errors.New("Could not generate a random key label.") } // Set the public key template // CKA_TOKEN: Guarantees key persistence in hardware // CKA_LABEL: Identifies this specific key inside of the HSM publicKeyTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, []byte{3}), pkcs11.NewAttribute(pkcs11.CKA_MODULUS_BITS, 2048), pkcs11.NewAttribute(pkcs11.CKA_LABEL, string(randomLabel)), } privateKeyTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), pkcs11.NewAttribute(pkcs11.CKA_LABEL, string(randomLabel)), } // Generate a new RSA private/public keypair inside of the HSM pub, priv, err := s.context.GenerateKeyPair(s.session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_KEY_PAIR_GEN, nil)}, publicKeyTemplate, privateKeyTemplate) if err != nil { return nil, errors.New("Could not generate a new key inside of the HSM.") } // (diogo): This template is used for the GetAttribute template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil), pkcs11.NewAttribute(pkcs11.CKA_MODULUS_BITS, nil), pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil), } // Retrieve the public-key material to be able to create a new HSMRSAKey attr, err := s.context.GetAttributeValue(s.session, pub, template) if err != nil { return nil, errors.New("Failed to get Attribute value.") } // We're going to store the elements of the RSA Public key, exponent and Modulus inside of exp and mod var exp int mod := big.NewInt(0) // Iterate through all the attributes of this key and saves CKA_PUBLIC_EXPONENT and CKA_MODULUS. Removes ordering specific issues. for _, a := range attr { if a.Type == pkcs11.CKA_PUBLIC_EXPONENT { exp, _ = readInt(a.Value) } if a.Type == pkcs11.CKA_MODULUS { mod.SetBytes(a.Value) } } rsaPublicKey := rsa.PublicKey{N: mod, E: exp} // Using x509 to Marshal the Public key into der encoding pubBytes, err := x509.MarshalPKIXPublicKey(&rsaPublicKey) if err != nil { return nil, errors.New("Failed to Marshal public key.") } // (diogo): Ideally I would like to return base64 PEM encoded public keys to the client k := keys.NewHSMRSAKey(pubBytes, priv) keyID := k.ID() s.keys[keyID] = k return k, nil }
func generate_pkcs11keypair() { config := configure() p := pkcs11.New(config.module) if p == nil { fmt.Printf("Could not initialize pkcs11 with module %s, exiting.\n", config.module) os.Exit(1) } p.Initialize() defer p.Destroy() defer p.Finalize() var used_slot uint = 0 slots, _ := p.GetSlotList(true) for _, slot_id := range slots { if slot_id == config.slot_id { used_slot = config.slot_id } } fmt.Printf("Wanted slot id %v ", config.slot_id) fmt.Printf("and got slot id %v.\n", used_slot) session, err := p.OpenSession(used_slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) if err != nil { fmt.Printf("Could not open session. Error: %v\n", err) os.Exit(1) } defer p.CloseSession(session) p.Login(session, pkcs11.CKU_USER, config.user_pin) defer p.Logout(session) info, err := p.GetInfo() if err != nil { fmt.Printf("GetInfo failed: %v\n", err) os.Exit(1) } else { fmt.Printf("HSM Info:\nManufacturer ID %v\nFlags: %v\nLibrary Description: %v\nLibrary Version: %v.\n", info.ManufacturerID, info.Flags, info.LibraryDescription, info.LibraryVersion) } // var pub_exponent int = 0x010001 publicKeyTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKO_PUBLIC_KEY), pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), pkcs11.NewAttribute(pkcs11.CKA_MODULUS_BITS, config.rsa_size), pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, []byte{3}), pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), pkcs11.NewAttribute(pkcs11.CKA_ENCRYPT, true), pkcs11.NewAttribute(pkcs11.CKA_WRAP, true), pkcs11.NewAttribute(pkcs11.CKA_LABEL, config.key_label), pkcs11.NewAttribute(pkcs11.CKA_ID, config.key_id), pkcs11.NewAttribute(pkcs11.CKA_SUBJECT, "/CN=Harald Wagener"), } privateKeyTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true), pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), pkcs11.NewAttribute(pkcs11.CKA_DECRYPT, true), pkcs11.NewAttribute(pkcs11.CKA_UNWRAP, true), pkcs11.NewAttribute(pkcs11.CKA_LABEL, config.key_label), pkcs11.NewAttribute(pkcs11.CKA_ID, config.key_id), pkcs11.NewAttribute(pkcs11.CKA_SUBJECT, "/CN=Harald Wagener"), } pub, priv, err := p.GenerateKeyPair(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_KEY_PAIR_GEN, nil)}, publicKeyTemplate, privateKeyTemplate) if err != nil { fmt.Printf("Error generating key pair: %v\n", err) os.Exit(1) } else { fmt.Printf("Key pair generated:\nPublic Key: %v\nPrivate Key: %v\n", pub, priv) os.Exit(0) } }
// Get the public key matching an Elliptic Curve private key func getECPublicKey(module ctx, session pkcs11.SessionHandle, privateKeyHandle pkcs11.ObjectHandle) (crypto.PublicKey, error) { var noKey interface{} // http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/os/pkcs11-curr-v2.40-os.html#_Toc416960012 template := []*pkcs11.Attribute{ // CKA_EC_PARAMS contains the OID of the curve (part of the // public key pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil), // CKA_ID will allow use to find the corresponding public key pkcs11.NewAttribute(pkcs11.CKA_ID, nil), } attr, err := module.GetAttributeValue(session, privateKeyHandle, template) if err != nil { return noKey, err } oid := []byte{} id := []byte{} gotOid, gotID := false, false for _, a := range attr { if a.Type == pkcs11.CKA_EC_PARAMS { oid = a.Value gotOid = true } else if a.Type == pkcs11.CKA_ID { id = a.Value gotID = true } } if !gotOid { return noKey, errors.New("private key missing curve parameters") } if !gotID { return noKey, errors.New("private key missing identifier (CKA_ID)") } poid := new(asn1.ObjectIdentifier) asn1.Unmarshal(oid, poid) curve := namedCurveFromOID(*poid) templateSearch := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), pkcs11.NewAttribute(pkcs11.CKA_ID, id), } if err := module.FindObjectsInit(session, templateSearch); err != nil { return noKey, err } objs, _, err := module.FindObjects(session, 1) if err != nil { return noKey, err } if err = module.FindObjectsFinal(session); err != nil { return noKey, err } if len(objs) == 0 { return noKey, fmt.Errorf("public key not found") } publicKeyHandle := objs[0] templatePub := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil), } attrPub, err := module.GetAttributeValue(session, publicKeyHandle, templatePub) if err != nil { return noKey, err } ecPoint := []byte{} gotEcPoint := false for _, a := range attrPub { if a.Type == pkcs11.CKA_EC_POINT { ecPoint = a.Value gotEcPoint = true } } if !gotEcPoint { return noKey, errors.New("public key missing EC Point") } x, y := readECPoint(curve, ecPoint) if x == nil { return noKey, errors.New("invalid EC Point") } ecdsa := ecdsa.PublicKey{ Curve: curve, X: x, Y: y, } return &ecdsa, nil }