Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
elm
element-web
matrix-js-sdk
Commits
c1d34f3a
Commit
c1d34f3a
authored
4 years ago
by
Bruno Windels
Browse files
Options
Download
Email Patches
Plain Diff
WIP
parent
1da959ab
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
412 additions
and
263 deletions
+412
-263
src/client.js
src/client.js
+0
-12
src/crypto/CrossSigning.js
src/crypto/CrossSigning.js
+3
-3
src/crypto/EncryptionSetup.js
src/crypto/EncryptionSetup.js
+225
-0
src/crypto/index.js
src/crypto/index.js
+184
-248
No files found.
src/client.js
View file @
c1d34f3a
...
...
@@ -1075,17 +1075,6 @@ function wrapCryptoFuncs(MatrixClient, names) {
}
}
/**
* Generate new cross-signing keys.
* The cross-signing API is currently UNSTABLE and may change without notice.
*
* @function module:client~MatrixClient#resetCrossSigningKeys
* @param {object} authDict Auth data to supply for User-Interactive auth.
* @param {CrossSigningLevel} [level] the level of cross-signing to reset. New
* keys will be created for the given level and below. Defaults to
* regenerating all keys.
*/
/**
* Get the user's cross-signing key ID.
* The cross-signing API is currently UNSTABLE and may change without notice.
...
...
@@ -1155,7 +1144,6 @@ function wrapCryptoFuncs(MatrixClient, names) {
* @param {module:models/room} room the room the event is in
*/
wrapCryptoFuncs
(
MatrixClient
,
[
"
resetCrossSigningKeys
"
,
"
getCrossSigningId
"
,
"
getStoredCrossSigningForUser
"
,
"
checkUserTrust
"
,
...
...
This diff is collapsed.
Click to expand it.
src/crypto/CrossSigning.js
View file @
c1d34f3a
...
...
@@ -178,12 +178,12 @@ export class CrossSigningInfo extends EventEmitter {
* typically called in conjunction with the creation of new cross-signing
* keys.
*
* @param {
object
} keys The keys to store
* @param {
Map
} keys The keys to store
* @param {SecretStorage} secretStorage The secret store using account data
*/
static
async
storeInSecretStorage
(
keys
,
secretStorage
)
{
for
(
const
type
of
Object
.
keys
(
keys
)
)
{
const
encodedKey
=
encodeBase64
(
keys
[
type
]
);
for
(
const
[
type
,
privateKey
]
of
keys
)
{
const
encodedKey
=
encodeBase64
(
privateKey
);
await
secretStorage
.
store
(
`m.cross_signing.
${
type
}
`
,
encodedKey
);
}
}
...
...
This diff is collapsed.
Click to expand it.
src/crypto/EncryptionSetup.js
0 → 100644
View file @
c1d34f3a
import
{
MatrixEvent
}
from
"
../models/event
"
;
import
{
EventEmitter
}
from
"
events
"
;
import
{
createCryptoStoreCacheCallbacks
}
from
"
./CrossSigning
"
;
import
{
IndexedDBCryptoStore
}
from
'
./store/indexeddb-crypto-store
'
;
import
{
PREFIX_UNSTABLE
,
}
from
"
../http-api
"
;
class
AccountDataClientAdapter
extends
EventEmitter
{
constructor
()
{
super
();
this
.
_values
=
new
Map
();
}
getAccountDataFromServer
(
type
)
{
return
Promise
.
resolve
(
this
.
_values
.
get
(
type
)
||
null
);
}
setAccountData
(
type
,
content
)
{
this
.
_values
.
set
(
type
,
content
);
Promise
.
resolve
().
then
(()
=>
{
const
event
=
new
MatrixEvent
({
type
,
content
});
this
.
emit
(
"
accountData
"
,
event
);
});
}
}
// implements both cache callbacks as non-cache callbacks
class
CrossSigningCallbacks
{
constructor
()
{
this
.
privateKeys
=
new
Map
();
}
// cache callbacks
getCrossSigningKeyCache
(
type
,
expectedPublicKey
)
{
return
this
.
getCrossSigningKey
(
type
,
expectedPublicKey
);
}
storeCrossSigningKeyCache
(
type
,
key
)
{
this
.
privateKeys
.
set
(
type
,
key
);
return
Promise
.
resolve
();
}
// non-cache callbacks
getCrossSigningKey
(
type
,
_expectedPubkey
)
{
return
Promise
.
resolve
(
this
.
privateKeys
.
get
(
type
));
}
saveCrossSigningKeys
(
privateKeys
)
{
for
(
const
[
type
,
privateKey
]
of
Object
.
entries
(
privateKeys
))
{
this
.
privateKeys
.
set
(
type
,
privateKey
);
}
}
}
class
SSSSCryptoCallbacks
{
constructor
()
{
this
.
_privateKeys
=
new
Map
();
}
getSecretStorageKey
({
keys
},
name
)
{
for
(
const
keyId
of
Object
.
keys
(
keys
))
{
const
privateKey
=
this
.
_privateKeys
.
get
(
keyId
);
if
(
privateKey
)
{
return
[
keyId
,
privateKey
];
}
}
}
addPrivateKey
(
keyId
,
privKey
)
{
this
.
_privateKeys
.
set
(
keyId
,
privKey
);
}
}
export
class
EncryptionSetupBuilder
{
constructor
()
{
// TODO: do we need to put in the previous 4S account data as well? so we can detect colliding id's?
this
.
accountDataClientAdapter
=
new
AccountDataClientAdapter
();
this
.
crossSigningCallbacks
=
new
CrossSigningCallbacks
();
this
.
ssssCryptoCallbacks
=
new
SSSSCryptoCallbacks
();
this
.
_crossSigningKeys
=
null
;
this
.
_keySignatures
=
null
;
this
.
_keyBackupInfo
=
null
;
}
addCrossSigningKeys
(
auth
,
keys
)
{
this
.
_crossSigningKeys
=
{
auth
,
keys
};
}
addSessionBackup
(
keyBackupInfo
)
{
this
.
_keyBackupInfo
=
keyBackupInfo
;
}
addSessionBackupPrivateKeyToCache
(
privateKey
)
{
this
.
_sessionBackupPrivateKey
=
privateKey
;
}
addKeySignature
(
userId
,
deviceId
,
signature
)
{
if
(
!
this
.
_keySignatures
)
{
this
.
_keySignatures
=
{};
}
const
userSignatures
=
this
.
_keySignatures
[
userId
]
||
{};
this
.
_keySignatures
[
userId
]
=
userSignatures
;
userSignatures
[
deviceId
]
=
signature
;
}
buildOperation
()
{
const
accountData
=
this
.
accountDataClientAdapter
.
_values
;
return
new
EncryptionSetupOperation
(
accountData
,
this
.
_crossSigningKeys
,
this
.
_keyBackupInfo
,
this
.
_keySignatures
,
);
}
async
persist
(
crypto
)
{
// store self_signing and user_signing private key in cache
const
cacheCallbacks
=
createCryptoStoreCacheCallbacks
(
crypto
.
_cryptoStore
);
for
(
const
type
of
[
"
self_signing
"
,
"
user_signing
"
])
{
// logger.log(`Cache ${type} cross-signing private key locally`);
const
privateKey
=
this
.
crossSigningCallbacks
.
privateKeys
.
get
(
type
);
await
cacheCallbacks
.
storeCrossSigningKeyCache
(
type
,
privateKey
);
}
// store session backup key in cache
if
(
this
.
_sessionBackupPrivateKey
)
{
await
crypto
.
storeSessionBackupPrivateKey
(
this
.
_sessionBackupPrivateKey
);
}
// store own cross-sign pubkeys as trusted
await
crypto
.
_cryptoStore
.
doTxn
(
'
readwrite
'
,
[
IndexedDBCryptoStore
.
STORE_ACCOUNT
],
(
txn
)
=>
{
console
.
log
(
"
EncryptionSetup: storing public keys as trusted locally
"
,
this
.
_crossSigningKeys
);
crypto
.
_cryptoStore
.
storeCrossSigningKeys
(
txn
,
this
.
_crossSigningKeys
.
keys
);
},
);
}
}
// this will be restored from idb in a future PR for retrying,
// it does not have knowledge of any private keys, unlike the builder.
export
class
EncryptionSetupOperation
{
constructor
(
accountData
,
crossSigningKeys
,
keyBackupInfo
,
keySignatures
)
{
this
.
_accountData
=
accountData
;
this
.
_crossSigningKeys
=
crossSigningKeys
;
this
.
_keyBackupInfo
=
keyBackupInfo
;
this
.
_keySignatures
=
keySignatures
;
}
hasAnythingToDo
()
{
if
(
this
.
_accountData
.
size
>
0
)
{
return
true
;
}
if
(
this
.
_crossSigningKeys
)
{
return
true
;
}
if
(
this
.
_keyBackupInfo
)
{
return
true
;
}
if
(
this
.
_keySignatures
)
{
return
true
;
}
return
false
;
}
async
apply
(
crypto
)
{
const
baseApis
=
crypto
.
_baseApis
;
// set account data
// (convert from Map to object for logging)
const
adData
=
Array
.
from
(
this
.
_accountData
.
entries
()).
reduce
((
obj
,
[
key
,
value
])
=>
{
obj
[
key
]
=
value
;
return
obj
;
},
{});
console
.
log
(
"
EncryptionSetup: apply account data
"
,
adData
);
for
(
const
[
type
,
content
]
of
this
.
_accountData
)
{
await
baseApis
.
setAccountData
(
type
,
content
);
}
// upload cross-signing keys
console
.
log
(
"
EncryptionSetup: uploading keys
"
,
this
.
_crossSigningKeys
);
if
(
this
.
_crossSigningKeys
)
{
const
keys
=
{};
for
(
const
[
name
,
key
]
of
Object
.
entries
(
this
.
_crossSigningKeys
.
keys
))
{
keys
[
name
+
"
_key
"
]
=
key
;
}
await
baseApis
.
uploadDeviceSigningKeys
(
this
.
_crossSigningKeys
.
auth
,
keys
,
);
// pass the new keys to the main instance of our own CrossSigningInfo.
crypto
.
_crossSigningInfo
.
setKeys
(
this
.
_crossSigningKeys
.
keys
);
}
// upload first cross-signing signatures with the new key
// (e.g. signing our own device)
if
(
this
.
_keySignatures
)
{
await
baseApis
.
uploadKeySignatures
(
this
.
_keySignatures
);
}
// session backup signature
// The backup is trusted because the user provided the private key.
// Sign the backup with the cross signing key so the key backup can
// be trusted via cross-signing.
//
console
.
log
(
"
EncryptionSetup: key backup
"
,
this
.
_keyBackupInfo
);
if
(
this
.
_keyBackupInfo
.
version
)
{
// update signatures on key backup
await
baseApis
.
_http
.
authedRequest
(
undefined
,
"
PUT
"
,
"
/room_keys/version/
"
+
this
.
_keyBackupInfo
.
version
,
undefined
,
{
algorithm
:
this
.
_keyBackupInfo
.
algorithm
,
auth_data
:
this
.
_keyBackupInfo
.
auth_data
,
},
{
prefix
:
PREFIX_UNSTABLE
},
);
}
else
{
// add new key backup
await
baseApis
.
_http
.
authedRequest
(
undefined
,
"
POST
"
,
"
/room_keys/version
"
,
undefined
,
this
.
_keyBackupInfo
,
{
prefix
:
PREFIX_UNSTABLE
},
);
}
}
}
This diff is collapsed.
Click to expand it.
src/crypto/index.js
View file @
c1d34f3a
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment