github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/secret_store_external.go (about) 1 // Copyright 2018 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 //go:build android 5 // +build android 6 7 package libkb 8 9 import ( 10 "errors" 11 "sync" 12 13 "github.com/keybase/client/go/kbcrypto" 14 "github.com/keybase/client/go/msgpack" 15 ) 16 17 // UnsafeExternalKeyStore is a simple interface that external clients can implement. 18 // It is unsafe because it returns raw bytes instead of the typed LKSecFullSecret 19 // Use with TypeSafeExternalKeyStoreProxy 20 type UnsafeExternalKeyStore interface { 21 RetrieveSecret(serviceName string, key string) ([]byte, error) 22 StoreSecret(serviceName string, key string, secret []byte) error 23 ClearSecret(serviceName string, key string) error 24 GetUsersWithStoredSecretsMsgPack(serviceName string) ([]byte, error) 25 SetupKeyStore(serviceName string, key string) error 26 } 27 28 // ExternalKeyStore is the interface for the actual (external) keystore. 29 type ExternalKeyStore interface { 30 RetrieveSecret(serviceName string, key string) (LKSecFullSecret, error) 31 StoreSecret(serviceName string, key string, secret LKSecFullSecret) error 32 ClearSecret(serviceName string, key string) error 33 GetUsersWithStoredSecretsMsgPack(serviceName string) ([]byte, error) 34 SetupKeyStore(serviceName string, key string) error 35 } 36 37 // TypeSafeExternalKeyStoreProxy wraps the UnsafeExternalKeyStore to provide 38 // the type-safe ExternalKeyStore interface to the rest of the code 39 type TypeSafeExternalKeyStoreProxy struct { 40 UnsafeExternalKeyStore UnsafeExternalKeyStore 41 } 42 43 func (w TypeSafeExternalKeyStoreProxy) RetrieveSecret(serviceName string, key string) (LKSecFullSecret, error) { 44 bytes, err := w.UnsafeExternalKeyStore.RetrieveSecret(serviceName, key) 45 if err != nil { 46 return LKSecFullSecret{}, err 47 } 48 49 return newLKSecFullSecretFromBytes(bytes) 50 } 51 52 func (w TypeSafeExternalKeyStoreProxy) StoreSecret(serviceName string, key string, secret LKSecFullSecret) error { 53 return w.UnsafeExternalKeyStore.StoreSecret(serviceName, key, secret.Bytes()) 54 } 55 56 func (w TypeSafeExternalKeyStoreProxy) ClearSecret(serviceName string, key string) error { 57 return w.UnsafeExternalKeyStore.ClearSecret(serviceName, key) 58 } 59 60 func (w TypeSafeExternalKeyStoreProxy) GetUsersWithStoredSecretsMsgPack(serviceName string) ([]byte, error) { 61 return w.UnsafeExternalKeyStore.GetUsersWithStoredSecretsMsgPack(serviceName) 62 } 63 64 func (w TypeSafeExternalKeyStoreProxy) SetupKeyStore(serviceName string, key string) error { 65 return w.UnsafeExternalKeyStore.SetupKeyStore(serviceName, key) 66 } 67 68 // externalKeyStore is the reference to some external key store 69 var externalKeyStore ExternalKeyStore 70 var externalKeyStoreInitialized bool 71 var externalKeyStoreMu sync.Mutex 72 73 // SetGlobalExternalKeyStore is called by Android to register Android's KeyStore with Go 74 func SetGlobalExternalKeyStore(s UnsafeExternalKeyStore) { 75 externalKeyStoreMu.Lock() 76 defer externalKeyStoreMu.Unlock() 77 externalKeyStore = TypeSafeExternalKeyStoreProxy{s} 78 externalKeyStoreInitialized = false 79 } 80 81 var errNoExternalKeyStore = errors.New("no external key store available") 82 83 func getGlobalExternalKeyStore(m MetaContext) (ExternalKeyStore, error) { 84 externalKeyStoreMu.Lock() 85 defer externalKeyStoreMu.Unlock() 86 87 if externalKeyStore == nil { 88 // perhaps SetGlobalExternalKeyStore has not been called by Android internals yet: 89 m.Debug("secret_store_external:getGlobalExternalKeyStore called, but externalKeyStore is nil") 90 return nil, errNoExternalKeyStore 91 } 92 93 // always check this since perhaps SetGlobalExternalKeyStore called more than once 94 if !externalKeyStoreInitialized { 95 m.Debug("+ secret_store_external:setup (in getGlobalExternalKeyStore)") 96 defer m.Debug("- secret_store_external:setup (in getGlobalExternalKeyStore)") 97 98 serviceName := m.G().GetStoredSecretServiceName() 99 100 // username not required 101 err := externalKeyStore.SetupKeyStore(serviceName, "") 102 if err != nil { 103 m.Debug("externalKeyStore.SetupKeyStore(%s) error: %s (%T)", serviceName, err, err) 104 return nil, err 105 } 106 107 m.Debug("externalKeyStore.SetupKeyStore(%s) success", serviceName) 108 externalKeyStoreInitialized = true 109 } 110 111 return externalKeyStore, nil 112 } 113 114 type secretStoreAndroid struct{} 115 116 var _ SecretStoreAll = &secretStoreAndroid{} 117 118 func (s *secretStoreAndroid) serviceName(m MetaContext) string { 119 return m.G().GetStoredSecretServiceName() 120 } 121 122 func (s *secretStoreAndroid) StoreSecret(m MetaContext, username NormalizedUsername, secret LKSecFullSecret) (err error) { 123 defer m.Trace("secret_store_external StoreSecret", &err)() 124 ks, err := getGlobalExternalKeyStore(m) 125 if err != nil { 126 return err 127 } 128 129 return ks.StoreSecret(s.serviceName(m), string(username), secret) 130 } 131 132 func (s *secretStoreAndroid) RetrieveSecret(m MetaContext, username NormalizedUsername) (sec LKSecFullSecret, err error) { 133 defer m.Trace("secret_store_external RetrieveSecret", &err)() 134 135 ks, err := getGlobalExternalKeyStore(m) 136 if err != nil { 137 return sec, err 138 } 139 140 return ks.RetrieveSecret(s.serviceName(m), string(username)) 141 } 142 143 func (s *secretStoreAndroid) ClearSecret(m MetaContext, username NormalizedUsername) (err error) { 144 defer m.Trace("secret_store_external ClearSecret", &err)() 145 if username.IsNil() { 146 m.Debug("NOOPing secretStoreAndroid#ClearSecret for empty username") 147 return nil 148 } 149 ks, err := getGlobalExternalKeyStore(m) 150 if err != nil { 151 return err 152 } 153 154 return ks.ClearSecret(s.serviceName(m), string(username)) 155 } 156 157 func (s *secretStoreAndroid) GetUsersWithStoredSecrets(m MetaContext) (users []string, err error) { 158 defer m.Trace("secret_store_external GetUsersWithStoredSecrets", &err)() 159 160 ks, err := getGlobalExternalKeyStore(m) 161 if err != nil { 162 if err == errNoExternalKeyStore { 163 // this is to match previous behavior of this function, 164 // but perhaps it should return the error instead 165 return nil, nil 166 } 167 return nil, err 168 } 169 usersMsgPack, err := ks.GetUsersWithStoredSecretsMsgPack(s.serviceName(m)) 170 if err != nil { 171 return nil, err 172 } 173 ch := kbcrypto.CodecHandle() 174 var usersUnpacked []string 175 err = msgpack.DecodeAll(usersMsgPack, ch, &usersUnpacked) 176 for _, v := range usersUnpacked { 177 if !isPPSSecretStore(v) { 178 users = append(users, v) 179 } 180 } 181 return users, err 182 } 183 184 func (s *secretStoreAndroid) GetOptions(MetaContext) *SecretStoreOptions { return nil } 185 func (s *secretStoreAndroid) SetOptions(MetaContext, *SecretStoreOptions) {}