@@ -169,10 +169,10 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address):
169169 return False
170170
171171def safeConfigGetBoolean (section ,field ):
172- try :
173- return config .getboolean (section ,field )
174- except :
175- return False
172+ try :
173+ return config .getboolean (section ,field )
174+ except :
175+ return False
176176
177177def decodeWalletImportFormat (WIFstring ):
178178 fullString = arithmetic .changebase (WIFstring ,58 ,256 )
@@ -196,22 +196,37 @@ def reloadMyAddressHashes():
196196 myECCryptorObjects .clear ()
197197 myAddressesByHash .clear ()
198198 #myPrivateKeys.clear()
199+
200+ keyfileSecure = checkSensitiveFilePermissions (appdata + 'keys.dat' )
199201 configSections = config .sections ()
200- hasExistingKeys = False
202+ hasEnabledKeys = False
201203 for addressInKeysFile in configSections :
202204 if addressInKeysFile <> 'bitmessagesettings' :
203- hasExistingKeys = True
205+ hasEnabledKeys = True
204206 isEnabled = config .getboolean (addressInKeysFile , 'enabled' )
205207 if isEnabled :
206- status ,addressVersionNumber ,streamNumber ,hash = decodeAddress (addressInKeysFile )
207- if addressVersionNumber == 2 or addressVersionNumber == 3 :
208- privEncryptionKey = decodeWalletImportFormat (config .get (addressInKeysFile , 'privencryptionkey' )).encode ('hex' ) #returns a simple 32 bytes of information encoded in 64 Hex characters, or null if there was an error
209- if len (privEncryptionKey ) == 64 :#It is 32 bytes encoded as 64 hex characters
210- myECCryptorObjects [hash ] = highlevelcrypto .makeCryptor (privEncryptionKey )
211- myAddressesByHash [hash ] = addressInKeysFile
208+ if keyfileSecure :
209+ status ,addressVersionNumber ,streamNumber ,hash = decodeAddress (addressInKeysFile )
210+ if addressVersionNumber == 2 or addressVersionNumber == 3 :
211+ # Returns a simple 32 bytes of information encoded in 64 Hex characters, or null if there was an error.
212+ privEncryptionKey = decodeWalletImportFormat (
213+ config .get (addressInKeysFile , 'privencryptionkey' )).encode ('hex' )
214+
215+ if len (privEncryptionKey ) == 64 :#It is 32 bytes encoded as 64 hex characters
216+ myECCryptorObjects [hash ] = highlevelcrypto .makeCryptor (privEncryptionKey )
217+ myAddressesByHash [hash ] = addressInKeysFile
218+ else :
219+ sys .stderr .write ('Error in reloadMyAddressHashes: Can\' t handle address versions other than 2 or 3.\n ' )
212220 else :
213- sys .stderr .write ('Error in reloadMyAddressHashes: Can\' t handle address versions other than 2 or 3.\n ' )
214- fixKeyfilePermissions (appdata + 'keys.dat' , hasExistingKeys )
221+ # Insecure keyfile permissions. Disable key.
222+ config .set (addressInKeysFile , 'enabled' , 'false' )
223+ try :
224+ if not keyfileSecure :
225+ with open (appdata + 'keys.dat' , 'wb' ) as keyfile :
226+ config .write (keyfile )
227+ except :
228+ print 'Failed to disable vulnerable keyfiles.'
229+ raise
215230
216231def reloadBroadcastSendersForWhichImWatching ():
217232 printLock .acquire ()
@@ -303,16 +318,14 @@ def fixPotentiallyInvalidUTF8Data(text):
303318 output = 'Part of the message is corrupt. The message cannot be displayed the normal way.\n \n ' + repr (text )
304319 return output
305320
306- # Fix keyfile permissions due to inappropriate umask during keys.dat creation.
307- def fixKeyfilePermissions (keyfile , hasExistingKeys ):
308- present_keyfile_permissions = os .stat (keyfile )[0 ]
309- keyfile_disallowed_permissions = stat .S_IRWXG | stat .S_IRWXO
310- if (present_keyfile_permissions & keyfile_disallowed_permissions ) != 0 :
311- allowed_keyfile_permissions = ((1 << 32 )- 1 ) ^ keyfile_disallowed_permissions
312- new_keyfile_permissions = (
313- allowed_keyfile_permissions & present_keyfile_permissions )
314- os .chmod (keyfile , new_keyfile_permissions )
315- if hasExistingKeys :
321+ def checkSensitiveFilePermissions (filename ):
322+ if sys .platform == 'win32' :
323+ # TODO: This might deserve extra checks by someone familiar with
324+ # Windows systems.
325+ fileSecure = True
326+ else :
327+ fileSecure = secureFilePermissions (filename )
328+ if not fileSecure :
316329 print
317330 print '******************************************************************'
318331 print '** !! WARNING !! **'
@@ -321,7 +334,37 @@ def fixKeyfilePermissions(keyfile, hasExistingKeys):
321334 print '** Your keyfiles were vulnerable to being read by other users **'
322335 print '** (including some untrusted daemons). You may wish to consider **'
323336 print '** generating new keys and discontinuing use of your old ones. **'
324- print '** The problem has been automatically fixed. **'
325- print '******************************************************************'
326- print
337+ print '** Your private keys have been disabled for your security, but **'
338+ print '** you may re-enable them using the "Your Identities" tab in **'
339+ print '** the default GUI or by modifying keys.dat such that your keys **'
340+ print '** show "enabled = true". **'
341+ try :
342+ fixSensitiveFilePermissions (filename )
343+ print '** The problem has been automatically fixed. **'
344+ print '******************************************************************'
345+ print
346+ except Exception , e :
347+ print '** Could NOT automatically fix permissions. **'
348+ print '******************************************************************'
349+ print
350+ raise
351+ return fileSecure
352+
353+
354+ # Checks sensitive file permissions for inappropriate umask during keys.dat creation.
355+ # (Or unwise subsequent chmod.)
356+ # Returns true iff file appears to have appropriate permissions.
357+ def secureFilePermissions (filename ):
358+ present_permissions = os .stat (filename )[0 ]
359+ disallowed_permissions = stat .S_IRWXG | stat .S_IRWXO
360+ return present_permissions & disallowed_permissions == 0
361+
362+ # Fixes permissions on a sensitive file.
363+ def fixSensitiveFilePermissions (filename ):
364+ present_permissions = os .stat (filename )[0 ]
365+ disallowed_permissions = stat .S_IRWXG | stat .S_IRWXO
366+ allowed_permissions = ((1 << 32 )- 1 ) ^ disallowed_permissions
367+ new_permissions = (
368+ allowed_permissions & present_permissions )
369+ os .chmod (filename , new_permissions )
327370
0 commit comments