Closed
Bug 650208
Opened 14 years ago
Closed 14 years ago
More considered handling of key generation
Categories
(Firefox :: Sync, defect)
Firefox
Sync
Tracking
()
RESOLVED
FIXED
mozilla6
People
(Reporter: rnewman, Assigned: rnewman)
References
Details
(Whiteboard: [verified in services])
Attachments
(10 files, 3 obsolete files)
|
5.24 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
1.70 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
12.15 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
42.57 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
7.80 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
6.85 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
13.11 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
36.60 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
11.76 KB,
patch
|
philikon
:
review+
|
Details | Diff | Splinter Review |
|
6.90 KB,
text/plain
|
Details |
Filing a new bug for this, because I don't want to attach patches to a tracking bug!
Per discussion on IRC, we'd like to mitigate the possibility for clients to get into inconsistent states with keys. That means:
* If we generate keys, call _freshStart to wipe the server
* If we generate keys, do so by generating them, uploading, then downloading them to verify round-tripping.
The former avoids the possibility of exchanging new keys while data encrypted with old keys remains on the server. The latter avoids the possibility of a server or client bug preventing the exchange of keys, whilst this client happily encrypts and uploads new records with those new keys.
Here come the patches...
| Assignee | ||
Comment 1•14 years ago
|
||
This avoids some code duplication, and more closely matches what the server and client do wrt rounding.
Attachment #526189 -
Flags: review?(philipp)
| Assignee | ||
Comment 2•14 years ago
|
||
Another improvement along the way.
Attachment #526190 -
Flags: review?(philipp)
| Assignee | ||
Comment 3•14 years ago
|
||
This allows tests to continue to pass when logic changes to require uploads during key generation, as well as verifying the contents of info/collections.
(In short, it makes more tests behave more like a Sync server.)
Attachment #526191 -
Flags: review?(philipp)
| Assignee | ||
Comment 4•14 years ago
|
||
This patch is purely:
:%s,\s\+$,,
Lots of trailing whitespace in a couple of files. I CANNAE STAND IT, CAP'N!
Attachment #526192 -
Flags: review?(philipp)
| Assignee | ||
Comment 5•14 years ago
|
||
Not marking as r? yet, because CrossWeave hasn't finished.
| Assignee | ||
Comment 6•14 years ago
|
||
CrossWeave passes with Part 4, but I'll spend a little time tomorrow (today!) doing some manual testing and considering.
| Assignee | ||
Updated•14 years ago
|
Whiteboard: [has patch][needs review philikon]
| Assignee | ||
Comment 7•14 years ago
|
||
Working on some minor improvements to Part 4, along with a specific set of tests.
This came to mind: if the server reports that it has no keys, but we have some, should we still generate new ones?
It seems like it would be better all-round to upload the ones we have and go through the usual redownload dance -- this results in a good chance that other clients can potentially do less work because their keys don't keep changing. (We should still wipe the server, though.)
On the other hand, this ideally should never happen...
Thoughts?
| Assignee | ||
Comment 8•14 years ago
|
||
This version still always generates new keys.
Attachment #526193 -
Attachment is obsolete: true
Attachment #526392 -
Flags: review?(philipp)
| Assignee | ||
Comment 9•14 years ago
|
||
Attachment #526393 -
Flags: review?(philipp)
| Assignee | ||
Comment 10•14 years ago
|
||
The engine disabling tests were failing, because we now strictly validate the server! Fixxored. All 98 tests pass.
Attachment #526411 -
Flags: review?(philipp)
Comment 11•14 years ago
|
||
Comment on attachment 526189 [details] [diff] [review]
Part 0: refactor timestamp logic in tests.
Nice.
>+// Use the same method that record.js does, which mirrors the server.
>+function new_timestamp()
>+ Math.round(Date.now() / 10) / 100;
>+
Would be nice to explain this with a few more words, along the lines of: server returns timestamps with 1/100 sec granularity, also note that this may not always be the case in the future. Bonus points for filing or finding the server bug that reduces the granularity to seconds and referring to it in the comment.
Also nit: braces + return statement for a function statement.
>- response.setHeader('X-Weave-Timestamp', ''+Date.now()/1000, false);
>+ response.setHeader('X-Weave-Timestamp', ''+new_timestamp(), false);
nit: s/''/""/ and spaces around operator
>- response.setHeader('X-Weave-Timestamp', ''+Date.now()/1000, false);
>+ response.setHeader('X-Weave-Timestamp',
>+ ''+(new_timestamp()),
>+ false);
ditto
Attachment #526189 -
Flags: review?(philipp) → review+
Updated•14 years ago
|
Attachment #526190 -
Flags: review?(philipp) → review+
Comment 12•14 years ago
|
||
Comment on attachment 526191 [details] [diff] [review]
Part 2: augment tests to actually track collections.
>+function login_handling(handler) {
>+ return function (request, response) {
>+ // btoa('johndoe:ilovejane') == am9obmRvZTppbG92ZWphbmU=
>+ // btoa('janedoe:ilovejohn') == amFuZWRvZTppbG92ZWpvaG4=
>+ let header = request.getHeader("Authorization");
>+ if (header &&
>+ header == "Basic am9obmRvZTppbG92ZWphbmU=" ||
>+ header == "Basic amFuZWRvZTppbG92ZWpvaG4=") {
>+ handler(request, response);
>+ } else {
>+ let body = "Unauthorized";
>+ response.setStatusLine(request.httpVersion, 401, "Unauthorized");
>+ response.bodyOutputStream.write(body, body.length);
>+ }
>+ };
> }
Can we steal btoa from one of the BackstagePasses, e.g:
btoa = Cu.import("resource://services-sync/util.js").btoa;
and get rid of those magic strings? Maybe we should even add something like this to head_http_server():
function basic_auth_header(user, password) {
return "Basic " + btoa(user + ":" + password);
}
Attachment #526191 -
Flags: review?(philipp) → review+
Comment 13•14 years ago
|
||
Comment on attachment 526192 [details] [diff] [review]
Part 3: whitespace!
<3
Attachment #526192 -
Flags: review?(philipp) → review+
| Assignee | ||
Comment 14•14 years ago
|
||
(In reply to comment #12)
> Can we steal btoa from one of the BackstagePasses, e.g:
Yeah, I didn't do that because I was primarily moving code around, rather than rewriting, but this is a good opportunity. Goodbye, magic strings.
| Assignee | ||
Comment 15•14 years ago
|
||
As promised, philikon!
Attachment #526807 -
Flags: review?(philipp)
Comment 16•14 years ago
|
||
Comment on attachment 526807 [details] [diff] [review]
Part 2b: clean up basic auth mess in tests.
byootifool
Attachment #526807 -
Flags: review?(philipp) → review+
| Assignee | ||
Comment 17•14 years ago
|
||
Updated•14 years ago
|
Attachment #526411 -
Flags: review?(philipp) → review+
| Assignee | ||
Comment 18•14 years ago
|
||
Explicitly don't set or use local WBO modification times for the keys that we upload. Everything comes from the server.
Attachment #526392 -
Attachment is obsolete: true
Attachment #526392 -
Flags: review?(philipp)
Attachment #526918 -
Flags: review?(philipp)
Comment 19•14 years ago
|
||
Comment on attachment 526392 [details] [diff] [review]
Part 4: implement discussed changes.
> /**
> * If `collections` (an array of strings) is provided, iterate
> * over it and generate random keys for each collection.
>+ * Create a WBO for the given data.
> */
>- generateNewKeys: function(collections) {
>+ newWBO: function(collections, def, lastModified, collection, id) {
s/def/defaultBundle/ for better readability.
Seems like this is a helper method, so let's make it pseudo private by prepending an underscore (_newWBO or _makeWBO).
>+ wbo.modified = lastModified;
>+ return wbo;
>+ },
wbo.modified is set by the server, not the client. See https://wiki.mozilla.org/Labs/Weave/Sync/1.1/API#Weave_Basic_Object_.28WBO.29. You can get rid of it and the lastModified parameter.
>+ /**
>+ * Create a WBO for the current keys.
>+ */
>+ asWBO: function(collection, id)
>+ this.newWBO(this._collections,
>+ this._default,
>+ this._lastModified,
>+ collection || "crypto",
>+ id || "keys"),
>+
Why are we pretending to allow other collections and ids than crypto/keys? We have so many other places where CollectionKeyManager hard codes those values, we might as well const them at the top and do it properly. Gets rid of those parameters too (here and in newWBO)
>+ /**
>+ * If `collections` (an array of strings) is provided, iterate
>+ * over it and generate random keys for each collection.
>+ */
>+ generateNewKeys: function(collections) {
>+ let newDefaultKey, newColls;
>+ [newDefaultKey, newColls] = this.newKeys(collections);
>+
>+ let modified = (Math.round(Date.now()/10)/100); this._default = newDefaultKey;
>+ this._collections = newColls;
>+ this._lastModified = modified;
>+ },
Ignoring the obviously missing newline, I'm worried about the _lastModified property here because we're comparing it to other stuff later. That's fine so long as that other stuff is local time, too. But then there's no reason to do the funny math rounding stuff that the server does. In fact, we should not have any of that in the client. The client should be completely oblivious to the server's time precision. Server time and client time should be considered as if there were in different Minkowski frames and cannot be compared without some sort of transformation. ;)
So I think the solution is to set _lastModified when we PUT the keys to the server. The PUT returns a timestamp, we use that to set _lastModified. We might want to promote it to a public property then.
Btw, I see another instance of that Math.round business in CollectionKeys.setContents(). Please get rid of it there, too! The 'modified' parameter should be mandatory there.
>+ /**
>+ * Generates new keys, but does not replace our local copy. Use this to
>+ * verify an upload before storing.
>+ */
>+ generateNewKeysWBO: function(collections, collection, id) {
>+ let newDefaultKey, newColls;
>+ [newDefaultKey, newColls] = this.newKeys(collections);
>+
>+ let modified = (Math.round(Date.now()/10)/100);
>+ return this.newWBO(newColls,
>+ newDefaultKey,
>+ modified,
>+ collection || "crypto",
>+ id || "keys");
Same as above (hard code collection, id).
> generateNewSymmetricKeys:
> function WeaveSvc_generateNewSymmetricKeys() {
>- this._log.info("Generating new keys....");
>- CollectionKeys.generateNewKeys();
>- let wbo = CollectionKeys.asWBO("crypto", "keys");
>+ this._log.info("Generating new keys WBO...");
>+ let wbo = CollectionKeys.generateNewKeysWBO();
>+ let modified = wbo.modified;
Get rid of wbo.modified here. It shouldn't exist at this point.
>+ if (CollectionKeys._lastModified != modified) {
This is the line that makes me shudder. This will pretty much always be true because CollectionKeys._lastModified will be server time and modified (= wbo.modified) will be local time (also, the aliasing of 'wbo.modified' to 'modified' makes it extra hard to understand what's going on).
Attachment #526392 -
Attachment is obsolete: false
| Assignee | ||
Comment 20•14 years ago
|
||
This should do it... running CrossWeave now. *fingers crossed*
Attachment #526392 -
Attachment is obsolete: true
Attachment #526918 -
Attachment is obsolete: true
Attachment #526918 -
Flags: review?(philipp)
Attachment #526928 -
Flags: review?(philipp)
| Assignee | ||
Comment 21•14 years ago
|
||
CrossWeave — sorry, TPS — passes locally.
| Assignee | ||
Comment 22•14 years ago
|
||
(In reply to comment #19)
> So I think the solution is to set _lastModified when we PUT the keys to the
> server.
We actually explicitly don't want to set in PUT, because we don't update the local keys when we upload our new WBO! We update lastModified (now a public property) in setContents, as soon as we're done validating the downloaded keys. This happens in the subsequent GET.
In short: CollectionKeys is always set from a WBO (in real code (and some tests) downloaded from the server; in other tests, bypassing the server round-trip), and the modified time comes from the same source.
Comment 23•14 years ago
|
||
Comment on attachment 526928 [details] [diff] [review]
Part 4: implement discussed changes. v3
Nice work!
> generateNewSymmetricKeys:
> function WeaveSvc_generateNewSymmetricKeys() {
...
>+ info = info.obj;
>+ if (!("crypto" in info)) {
CRYPTO_COLLECTION
>+ this._log.error("Consistency failure: info/collections excludes " +
>+ "crypto after successful upload.");
>+ throw new Error("Symmetric key upload failed.");
>+ }
>+
>+ // Can't check against local modified: clock drift.
>+ if (info.crypto < serverModified) {
CRYPTO_COLLECTION
r=me with that
Attachment #526928 -
Flags: review?(philipp) → review+
Comment 24•14 years ago
|
||
Comment on attachment 526393 [details] [diff] [review]
Part 5: additional test for freshStart.
Please use run_next_test instead of do_test_pending/do_test_finished. r=me with that.
Attachment #526393 -
Flags: review?(philipp) → review+
| Assignee | ||
Comment 25•14 years ago
|
||
| Assignee | ||
Comment 26•14 years ago
|
||
Mini follow-up to address Comment 23.
Attachment #527075 -
Flags: review?(philipp)
Updated•14 years ago
|
Attachment #527075 -
Flags: review?(philipp) → review+
| Assignee | ||
Comment 27•14 years ago
|
||
Whiteboard: [has patch][needs review philikon] → [fixed in services]
| Assignee | ||
Comment 28•14 years ago
|
||
Can't think of any STR for most of this -- it would require two racing clients. There are automated tests, at least!
I seem to recall an earlier bug when I wrote STR that involved wiping keys… will look.
| Assignee | ||
Comment 29•14 years ago
|
||
Ah, I was thinking of Bug 642727. Those STR are no longer viable, so here are some new ones:
* Set up Sync on two machines. Sync both as usual.
* On one machine, open a privileged web console:
const Cu = Components.utils;
Cu.import("resource://services-sync/resource.js");
var svc = Cu.import("resource://services-sync/service.js").Service;
new Resource(svc.storageURL + "crypto").delete();
This will delete keys from the server. You can ignore the output.
* Sync. Observe that the log on that machine has a huge pile of text like the attachment.
Comment 30•14 years ago
|
||
verified in s-c builds of 1303795082
Whiteboard: [fixed in services] → [verified in services]
Comment 31•14 years ago
|
||
Part 0: https://hg.mozilla.org/mozilla-central/rev/e7560f6fcc8f
Part 1: https://hg.mozilla.org/mozilla-central/rev/e71e755ed1e2
Part 2: https://hg.mozilla.org/mozilla-central/rev/053e21ba8d5a
Part 2b: https://hg.mozilla.org/mozilla-central/rev/1ac10c3832b6
Part 3: https://hg.mozilla.org/mozilla-central/rev/a8e836c166e0
Part 4: https://hg.mozilla.org/mozilla-central/rev/c79e44ac168c
Part 5: https://hg.mozilla.org/mozilla-central/rev/9fd1441dfc34
Part 6: https://hg.mozilla.org/mozilla-central/rev/bc93f7962f69
Status: ASSIGNED → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla6
Comment 32•14 years ago
|
||
Updated•7 years ago
|
Component: Firefox Sync: Backend → Sync
Product: Cloud Services → Firefox
You need to log in
before you can comment on or make changes to this bug.
Description
•