func (s *ssProvider) Set(c, u, p string) error { var item, prompt dbus.ObjectPath properties := map[string]dbus.Variant{ "org.freedesktop.Secret.Item.Label": dbus.MakeVariant(fmt.Sprintf("%s - %s", u, c)), "org.freedesktop.Secret.Item.Attributes": dbus.MakeVariant(map[string]string{ "username": u, "service": c, }), } session, err := s.openSession() if err != nil { return err } defer session.Call(fmt.Sprint(ssSessionIface, "Close"), 0) s.unlock(ssCollectionPath) collection := s.Object(ssServiceName, ssCollectionPath) secret := newSSSecret(session.Path(), p) // the bool is "replace" err = collection.Call(fmt.Sprint(ssCollectionIface, "CreateItem"), 0, properties, secret, true).Store(&item, &prompt) if err != nil { return fmt.Errorf("keyring/dbus: CreateItem error: %s", err) } if prompt != "/" { s.Object(ssServiceName, prompt).Call(fmt.Sprint(ssPromptIface, "Prompt"), 0, "unlock") } return nil }
// The first argument is the Label for the collection, and the second is an (optional) alias. func (s Service) CreateCollection(label, alias string) (Collection, error) { // spec: CreateCollection(IN Dict<String,Variant> properties, IN String alias, OUT ObjectPath collection, OUT ObjectPath prompt); var collectionPath, promptPath dbus.ObjectPath conn, err := dbus.SessionBus() if err != nil { return Collection{}, err } properties := map[string]dbus.Variant{ _CollectionLabel: dbus.MakeVariant(label), } call := s.Call(_ServiceCreateCollection, 0, properties, alias) if call.Err != nil { return Collection{}, call.Err } err = call.Store(&collectionPath, &promptPath) if err != nil { return Collection{}, err } if dbus.ObjectPath("/") != collectionPath { return Collection{conn.Object(ServiceName, collectionPath)}, nil } v, err := checkPrompt(promptPath) if err != nil { return Collection{}, err } return Collection{conn.Object(ServiceName, dbus.ObjectPath(v.Value().(string)))}, fmt.Errorf("unable to create collection") }
// First argument is the algorithm used. "plain" (AlgoPlain) and // "dh-ietf1024-sha256-aes128-cbc-pkcs7" (AlgoDH) are supported. // // The dbus api has the caller supply their DH public key and returns // the other side's public key, but this implementation generates a // new keypair, does the exchange, derives the encryption key, and then // stores it in the returned Session. func (s Service) OpenSession(algo string, args ...interface{}) (Session, error) { // spec: OpenSession(IN String algorithm, IN Variant input, OUT Variant output, OUT ObjectPath result); var ret Session conn, err := dbus.SessionBus() if err != nil { return ret, err } switch algo { case AlgoPlain: var discard dbus.Variant var sessionPath dbus.ObjectPath err = s.Call(_ServiceOpenSession, 0, algo, dbus.MakeVariant("")).Store(&discard, &sessionPath) if err != nil { return ret, err } ret = Session{conn.Object(ServiceName, sessionPath), algo, nil} case AlgoDH: // see http://standards.freedesktop.org/secret-service/ch07s03.html var sessionPath dbus.ObjectPath var srvReply dbus.Variant var srvPub []byte symKey := make([]byte, aes.BlockSize) grp, err := dhkx.GetGroup(2) if err != nil { return ret, err } privKey, err := grp.GeneratePrivateKey(rand.Reader) if err != nil { return ret, err } err = s.Call(_ServiceOpenSession, 0, algo, dbus.MakeVariant(privKey.Bytes())).Store(&srvReply, &sessionPath) if err != nil { return ret, err } srvPub = srvReply.Value().([]byte) sharedKey, err := grp.ComputeKey(dhkx.NewPublicKey(srvPub), privKey) if err != nil { return ret, err } _, err = io.ReadFull(hkdf.New(sha256.New, sharedKey.Bytes(), nil, nil), symKey) ret = Session{conn.Object(ServiceName, sessionPath), algo, symKey} default: err = InvalidAlgorithm } return ret, err }
// This is used to open a seassion for every get/set. Alternative might be to // defer() the call to close when constructing the ssProvider func (s *ssProvider) openSession() (*dbus.Object, error) { var disregard dbus.Variant var sessionPath dbus.ObjectPath method := fmt.Sprint(ssServiceIface, "OpenSession") err := s.srv.Call(method, 0, "plain", dbus.MakeVariant("")).Store(&disregard, &sessionPath) if err != nil { return nil, err } return s.Object(ssServiceName, sessionPath), nil }
func (c Collection) CreateItem(label string, attr map[string]string, s Secret, replace bool) (Item, error) { // spec: CreateItem(IN Dict<String,Variant> properties, IN Secret secret, IN Boolean replace, OUT ObjectPath item, OUT ObjectPath prompt); i := Item{} conn, err := dbus.SessionBus() if err != nil { return i, err } prop := make(map[string]dbus.Variant) prop[_ItemLabel] = dbus.MakeVariant(label) prop[_ItemAttributes] = dbus.MakeVariant(attr) call := c.Call(_CollectionCreateItem, 0, prop, s, replace) if call.Err != nil { return i, call.Err } var newItem dbus.ObjectPath call.Store(&newItem) i = Item{conn.Object(ServiceName, newItem)} return i, nil }