Merge lp:~mir-team/mir/attestable-timestamps-server into lp:mir
- attestable-timestamps-server
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alan Griffiths |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2943 |
Proposed branch: | lp:~mir-team/mir/attestable-timestamps-server |
Merge into: | lp:mir |
Diff against target: |
1375 lines (+951/-5) 32 files modified
CMakeLists.txt (+1/-0) cmake/ABICheck.cmake (+2/-1) debian/control (+28/-0) debian/libmircookie-dev.install (+3/-0) debian/libmircookie1.install (+1/-0) debian/mir-test-tools.install (+1/-0) include/cookie/mir/cookie_factory.h (+104/-0) include/cookie/mir_toolkit/cookie.h (+44/-0) include/server/mir/server.h (+12/-0) include/test/mir_test_framework/executable_path.h (+1/-0) src/CMakeLists.txt (+3/-0) src/cookie/CMakeLists.txt (+48/-0) src/cookie/cookie_factory.cpp (+161/-0) src/cookie/mircookie.pc.in (+11/-0) src/cookie/symbols.map (+9/-0) src/include/server/mir/default_server_configuration.h (+7/-1) src/include/server/mir/server_configuration.h (+5/-0) src/server/CMakeLists.txt (+2/-1) src/server/default_server_configuration.cpp (+21/-1) src/server/server.cpp (+17/-0) src/server/symbols.map (+2/-0) tests/acceptance-tests/CMakeLists.txt (+3/-0) tests/include/mir_test_framework/udev_environment.h (+26/-0) tests/integration-tests/CMakeLists.txt (+1/-0) tests/mir_test_framework/CMakeLists.txt (+4/-0) tests/mir_test_framework/executable_path.cpp (+13/-0) tests/mir_test_framework/udev_environment.cpp (+38/-1) tests/mir_test_framework/udev_recordings/CMakeLists.txt (+3/-0) tests/mir_test_framework/udev_recordings/laptop-keyboard-hello.evemu (+272/-0) tests/unit-tests/CMakeLists.txt (+2/-0) tests/unit-tests/test_mir_cookie.cpp (+105/-0) tools/update_package_abis.sh (+1/-0) |
To merge this branch: | bzr merge lp:~mir-team/mir/attestable-timestamps-server |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tyler Hicks (community) | Needs Fixing | ||
Brandon Schaefer (community) | Approve | ||
Andreas Pokorny (community) | Approve | ||
Alexandros Frantzis (community) | Approve | ||
Kevin DuBois (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Alan Griffiths | Approve | ||
Chris Halse Rogers | Approve | ||
Review via email: mp+270457@code.launchpad.net |
Commit message
server: Added a CookieFactory which generates macs for keyboard/motions events.
library: CookieFactory creates macs based on timestamp info
Description of the change
Splitting most the server bits from here:
https:/
The main parts are:
CookieFactory library
Integration with the server (init the cookie factory by seeding it with a random key)
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2911
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Brandon Schaefer (brandontschaefer) wrote : | # |
From the other review:
AFAICS libmircookie is only used by libmirserver.
What is the advantage to having a shared library over linking the code directly into libmirserver?
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2912
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2912
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
+std::string mir_test_
+{
+ std::string bin_path = MIR_BUILD_
+ std::string share_path = MIR_INSTALL_
+
+ if (boost:
+ return bin_path;
+ else if (boost:
+ return share_path;
+
+ BOOST_THROW_
+}
Can this really be the right behaviour? An installed test binary looks in the location where it was built? Even though a developer may be making changes there to compare results with.
~~~~
+ char const* RANDOM_DEVICE_PATH = "/dev/random";
+ int const WAIT_SECONDS = 30;
...
+ int const MAX_WAIT = 4;
http://
~~~~
AFAICS libmircookie is only used by libmirserver.
What is the advantage to having a shared library over linking the code directly into libmirserver?
~~~~
/mir/tests/
int const MAX_WAIT = 4;
^
1 error generated.
Brandon Schaefer (brandontschaefer) wrote : | # |
>
> +std::string mir_test_
> +{
> + std::string bin_path = MIR_BUILD_
> + std::string share_path = MIR_INSTALL_
> +
> + if (boost:
> + return bin_path;
> + else if (boost:
> + return share_path;
> +
> + BOOST_THROW_
> in standard search locations"));
> +}
>
> Can this really be the right behaviour? An installed test binary looks in the
> location where it was built? Even though a developer may be making changes
> there to compare results with.
I should check the share folder first. Other then that... I think its correct behaviour. We still want to be able to test it in a build directory. Unless I add an env variable that we set for the test it self. Let me know which one you would like!
>
> ~~~~
>
> + char const* RANDOM_DEVICE_PATH = "/dev/random";
> + int const WAIT_SECONDS = 30;
> ...
> + int const MAX_WAIT = 4;
>
> http://
> t_Names
>
I need to read through the coding standard for mir :). Use to compiz/unity7/nux.
> ~~~~
>
> AFAICS libmircookie is only used by libmirserver.
>
> What is the advantage to having a shared library over linking the code
> directly into libmirserver?
>
This is how it currently stands but we are planning on using this for the content hub as well. So best to keep it shared now, as it will be used by something else.
> ~~~~
>
> /mir/tests/
> 'MAX_WAIT' [-Werror,
> int const MAX_WAIT = 4;
> ^
> 1 error generated.
Thanks! Missed removing that.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2913
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
Sorry about the long list here, most of it is about fitting in with the design styles that have grown in Mir and you would not yet be familiar with. I've voted "Needs Fixing" but many of the points might be addressed by discussion.
~~~~
src/server/
There's a lot of code added here (to generate a seed) that probably doesn't belong in a translation unit that is about constructing the right objects to configure the system. I'd prefer to see it put in a separate file. (Is there any reason it can't be part of the new library?)
~~~~
+void fill_vector_
Could we not use a return value instead of an out parameter?
~~~~
+std::string mir_test_
+{
+ std::string share_path = MIR_INSTALL_
+ std::string bin_path = MIR_BUILD_
+
+ if (boost:
+ return share_path;
+ else if (boost:
+ return bin_path;
+
+ BOOST_THROW_
+}
Can this be right? A development test binary looks in the location where it would be installed? Even though a developer may be making changes to the version in the build path.
The older logic (based on the executable path) seems less surprising.
~~~~
+class CookieFactory
+{
+public:
+ CookieFactory(
+ ~CookieFactory() noexcept;
+
+ MirCookie timestamp_
+
+ bool attest_
+
+private:
+ class CookieImpl;
+ std::unique_
+};
What is the reason for preferring the Cheshire Cat idiom over Interface Class? This makes it far harder to substitute alternative implementations (e.g. for testing that cookies actually are validated when necessary).
I can also imagine a desire to provide a different verification model in a (hypothetical) downstream server.
~~~~~
+void mir::Server:
+{
+ verify_
+ self->cookie_
+}
It is a little surprising that this sets the cookie factory, not the secret. I can't immediately think of anything this breaks but...
Between this and the previous, I think this would fit better into Mir's design patterns if:
1. CookieFactory were an interface and CookieImpl a derived class.
2. the configuration point were override_
~~~~~
=== added file 'tests/
This reads more like a unit test
~~~~~
+ mir_discover_
The acceptance tests (before and after this MP) don't need libumockdev-
~~~~~
AFAICS the_cookie_
Brandon Schaefer (brandontschaefer) wrote : | # |
> Sorry about the long list here, most of it is about fitting in with the design
> styles that have grown in Mir and you would not yet be familiar with. I've
> voted "Needs Fixing" but many of the points might be addressed by discussion.
>
> ~~~~
>
No problem at all :), Thanks for going through in depth!
> src/server/
>
> There's a lot of code added here (to generate a seed) that probably doesn't
> belong in a translation unit that is about constructing the right objects to
> configure the system. I'd prefer to see it put in a separate file. (Is there
> any reason it can't be part of the new library?)
>
> ~~~~
This is true, Im not 100% sure why it cant be in the library it self. Ill have to talk to Chris about that.
>
> +void fill_vector_
>
> Could we not use a return value instead of an out parameter?
>
> ~~~~
Changed!
>
> +std::string mir_test_
> +{
> + std::string share_path = MIR_INSTALL_
> + std::string bin_path = MIR_BUILD_
> +
> + if (boost:
> + return share_path;
> + else if (boost:
> + return bin_path;
> +
> + BOOST_THROW_
> in standard search locations"));
> +}
>
> Can this be right? A development test binary looks in the location where it
> would be installed? Even though a developer may be making changes to the
> version in the build path.
>
> The older logic (based on the executable path) seems less surprising.
>
> ~~~~
Yes... Hmm so my overall thought here is do we need to always install the file to run the tests? Or should we ever be able to run the tests on a build directory? If we just want the test to run off the install location im 100% fine with that. All else I can think about is setting an env variable so we can run it to the build directory (and the test can set it).
Either way im happy to change it.
>
> +class CookieFactory
> +{
> +public:
> + CookieFactory(
> + ~CookieFactory() noexcept;
> +
> + MirCookie timestamp_
> +
> + bool attest_
> +
> +private:
> + class CookieImpl;
> + std::unique_
> +};
>
> What is the reason for preferring the Cheshire Cat idiom over Interface Class?
> This makes it far harder to substitute alternative implementations (e.g. for
> testing that cookies actually are validated when necessary).
>
> I can also imagine a desire to provide a different verification model in a
> (hypothetical) downstream server.
>
> ~~~~~
Not sure the reasoning here, Ill have to talk to Chris about it. Wouldnt be to hard to switch over to just an interface.
>
> +void mir::Server:
> +{
> + verify_
> + self->cookie_
> +}
>
> It is a little surprising that this sets the cookie factory, n...
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2914
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2915
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Chris Halse Rogers (raof) wrote : | # |
> What is the reason for preferring the Cheshire Cat idiom over Interface Class?
> This makes it far harder to substitute alternative implementations (e.g. for
> testing that cookies actually are validated when necessary).
>
> I can also imagine a desire to provide a different verification model in a
> (hypothetical) downstream server.
libmircookie is going to be used by Content Hub; Mir will share the secret with CH, and then CH will be able to verify cookies sent to it (for copy/paste and drag/drop operations). This is why it's a split-out library.
As such, it's actively harmful for downstream servers to override the implementation, as multiple processes need to agree on the method to verify cookies.
As an added bonus feature, it also means that libmircookie can have an actual ABI that's stable even under mild code churn :).
> Can this be right? A development test binary looks in the location where it
> would be installed? Even though a developer may be making changes to the
> version in the build path.
>
> The older logic (based on the executable path) seems less surprising.
Yeah, I'd have the test look first in the bin dir and *then* in the system-install location.
> src/server/
>
> There's a lot of code added here (to generate a seed) that probably doesn't
> belong in a translation unit that is about constructing the right objects to
> configure the system. I'd prefer to see it put in a separate file. (Is there
> any reason it can't be part of the new library?)
I'd have no objections to it being in the new library.
Other comments:
+ * This is not in any way cryptographically secure. This DOES NOT provide security.
We should drop this bit of the comment.
Once the above are dealt with: approve.
We should probably add a debian/
Chris Halse Rogers (raof) wrote : | # |
Oh, whitespace before '}':
362 + MirCookie cookie { timestamp, 0};
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2916
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2919
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2920
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
> > I can also imagine a desire to provide a different verification model in a
> > (hypothetical) downstream server.
>
> libmircookie is going to be used by Content Hub; Mir will share the secret
> with CH, and then CH will be able to verify cookies sent to it (for copy/paste
> and drag/drop operations). This is why it's a split-out library.
>
> As such, it's actively harmful for downstream servers to override the
> implementation, as multiple processes need to agree on the method to verify
> cookies.
Oh, I agree that within a UI stack it ought to be fixed. Just imagining that someone /could/ want a different implementation in a different stack.
> As an added bonus feature, it also means that libmircookie can have an actual
> ABI that's stable even under mild code churn :).
OK, that's an argument for a separate library. In fact, is it really something that will need to be released with every Mir release? Or should it be a separate project?
BTW this last argument doesn't address the "Cheshire Cat vs Interface" point. The ABI could easily be:
std::unique_
std::unique_
Alan Griffiths (alan-griffiths) wrote : | # |
> > === added file 'tests/
> >
> > This reads more like a unit test
> >
> > ~~~~~
> test_cookie_factory sound any better? (Im bad at names)
You misunderstand, I mean the test body reads like a unit test, not a test of the system.
Brandon Schaefer (brandontschaefer) wrote : | # |
O yeah sorry, I was planning on moving all those tests to unit tests in the client code ... but i should do that now and save on diff +/- :)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2921
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2922
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
+namespace mir
+{
...
+class CookieFactory
...
+std::vector<
We reserve the general mir namespace for system setup. These could be in a "cookie" namespace.
~~~~
+class CookieFactory
+{
+public:
+ CookieFactory(
+ ~CookieFactory() noexcept;
+
+ MirCookie timestamp_
+
+ bool attest_
+
+private:
+ class CookieImpl;
+ std::unique_
+};
I'm still not convinced we should prefer the Cheshire Cat idiom (over Interface Class) here, but if we are taking this approach then impl should be const.
~~~~
+std::string mir_test_
+{
+ std::string bin_path = MIR_BUILD_
+ std::string share_path = MIR_INSTALL_
+
+ if (boost:
+ return bin_path;
+ else if (boost:
+ return share_path;
+
+ BOOST_THROW_
+}
Can this really be the right behaviour? An installed test binary looks in the location where it was built? Even though a developer may be making changes there?
The older logic (based on the executable path) seems less surprising.
~~~~
+ CookieFactory(
This will throw if the secret is too small, but the behaviour and minimum size is not documented anywhere.
I suggest providing a static class member (minimum_
Alan Griffiths (alan-griffiths) wrote : | # |
Is libmircookie really something that will need to be released in sync with every Mir release? Or should it be a separate project?
~~~~
+std::vector<
Could be:
CookieFactory:
~~~~
+void mir::Server:
+{
+ verify_
+ self->cookie_
+}
It is a little surprising that this sets the cookie factory, not the secret.
Brandon Schaefer (brandontschaefer) wrote : | # |
> Is libmircookie really something that will need to be released in sync with
> every Mir release? Or should it be a separate project?
I dont have a clear answer for this one. I just imagine since the project is pretty small it makes it easier to keep it in lp:mir atm? Will have to poke raof about that one.
>
> ~~~~
>
> +std::vector<
>
> Could be:
>
> CookieFactory:
>
I had this at first, but switched up because one of the primary use-cases for CookieFactory is when you've shared the secret with another process, which you can't do if you've called CookieFactory(
> ~~~~
>
> +void mir::Server:
> +{
> + verify_
> + self->cookie_
> +}
>
> It is a little surprising that this sets the cookie factory, not the secret.
I think this function should just be renamed to initialize_
Brandon Schaefer (brandontschaefer) wrote : | # |
> +namespace mir
> +{
> ...
> +class CookieFactory
> ...
> +std::vector<
>
> We reserve the general mir namespace for system setup. These could be in a
> "cookie" namespace.
>
> ~~~~
Done.
>
> +class CookieFactory
> +{
> +public:
> + CookieFactory(
> + ~CookieFactory() noexcept;
> +
> + MirCookie timestamp_
> +
> + bool attest_
> +
> +private:
> + class CookieImpl;
> + std::unique_
> +};
>
> I'm still not convinced we should prefer the Cheshire Cat idiom (over
> Interface Class) here, but if we are taking this approach then impl should be
> const.
>
> ~~~~
Move to an NVI idiom:
http://
>
> +std::string mir_test_
> +{
> + std::string bin_path = MIR_BUILD_
> + std::string share_path = MIR_INSTALL_
> +
> + if (boost:
> + return bin_path;
> + else if (boost:
> + return share_path;
> +
> + BOOST_THROW_
> in standard search locations"));
> +}
>
> Can this really be the right behaviour? An installed test binary looks in the
> location where it was built? Even though a developer may be making changes
> there?
>
> The older logic (based on the executable path) seems less surprising.
>
> ~~~~
Not sure what the correct answer is here. What would be the best solution?
>
> + CookieFactory(
>
> This will throw if the secret is too small, but the behaviour and minimum size
> is not documented anywhere.
>
> I suggest providing a static class member (minimum_
> documenting the requirement.
Done.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2925
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2925
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
> > +std::vector<
> >
> > Could be:
> >
> > CookieFactory:
> >
>
> I had this at first, but switched up because one of the primary use-cases for
> CookieFactory is when you've shared the secret with another process, which you
> can't do if you've called CookieFactory(
I was thinking two constructors would be:
explicit CookieFactory(
explicit CookieFactory(
But I take your point - you need access to the "random data" to share the secret.
Alan Griffiths (alan-griffiths) wrote : | # |
> > Is libmircookie really something that will need to be released in sync with
> > every Mir release? Or should it be a separate project?
>
> I dont have a clear answer for this one. I just imagine since the project is
> pretty small it makes it easier to keep it in lp:mir atm? Will have to poke
> raof about that one.
A further thought, the header is dependent on MirCookie (introduced here into include/
As we're introducing this dependency on mircommon, could we just put the code into libmircommon and not a separate library?
Or should MirCookie be defined in libmircookie-dev and not libmircommon-dev?
Alan Griffiths (alan-griffiths) wrote : | # |
+#include <nettle/hmac.h>
...
+ struct hmac_sha1_ctx ctx;
Surely we don't want to introduce this dependency to user code? (See [1].)
There is no point in this class heirarchy if you are putting the derived class definition in the same header.
An option to consider here would the Named Constructor Idiom.
~~~~
+// Using the NVI Idiom
Nobody takes NVPI seriously - it is a solution in search of a problem.
The principle options to consider are Interface and Cheshire Cat (a.k.a. Pimpl). For a comparison of the different options see[2].
~~~~~
+ CookieFactoryNe
This will throw if the secret is too small, but the behaviour and minimum size is not documented in a doc comment on the function. (Having a non-doc comment in the private section of the class doesn't help the user.)
(But as I don't think this class should be made public anyway the documentation should go on the corresponding factory function.)
~~~~
> > The older logic (based on the executable path) seems less surprising.
> >
> > ~~~~
>
> Not sure what the correct answer is here. What would be the best solution?
I think to first check relative to the executable path (as it did before this MP), then to check the install location.
E.g. if running from a build directory it should pick up the one from e.g. <build>
~~~~
[1] http://
[2] http://
Brandon Schaefer (brandontschaefer) wrote : | # |
> +#include <nettle/hmac.h>
> ...
> + struct hmac_sha1_ctx ctx;
>
> Surely we don't want to introduce this dependency to user code? (See [1].)
>
> There is no point in this class heirarchy if you are putting the derived class
> definition in the same header.
>
> An option to consider here would the Named Constructor Idiom.
Done.
>
> ~~~~
>
> +// Using the NVI Idiom
>
> Nobody takes NVPI seriously - it is a solution in search of a problem.
>
> The principle options to consider are Interface and Cheshire Cat (a.k.a.
> Pimpl). For a comparison of the different options see[2].
>
> ~~~~~
Done.
>
> + CookieFactoryNe
>
> This will throw if the secret is too small, but the behaviour and minimum size
> is not documented in a doc comment on the function. (Having a non-doc comment
> in the private section of the class doesn't help the user.)
>
> (But as I don't think this class should be made public anyway the
> documentation should go on the corresponding factory function.)
>
> ~~~~
Done.
>
> > > The older logic (based on the executable path) seems less surprising.
> > >
> > > ~~~~
> >
> > Not sure what the correct answer is here. What would be the best solution?
>
> I think to first check relative to the executable path (as it did before this
> MP), then to check the install location.
>
> E.g. if running from a build directory it should pick up the one from e.g.
> <build>
>
> ~~~~
Done.
>
> [1] http://
>
> [2] http://
Thanks! Those were good reads. If you've more articles, I would be more then happy to read :).
Brandon Schaefer (brandontschaefer) wrote : | # |
> > > Is libmircookie really something that will need to be released in sync
> with
> > > every Mir release? Or should it be a separate project?
> >
> > I dont have a clear answer for this one. I just imagine since the project is
> > pretty small it makes it easier to keep it in lp:mir atm? Will have to poke
> > raof about that one.
>
> A further thought, the header is dependent on MirCookie (introduced here into
> include/
> dependent on libmircommon-dev.
>
> As we're introducing this dependency on mircommon, could we just put the code
> into libmircommon and not a separate library?
>
> Or should MirCookie be defined in libmircookie-dev and not libmircommon-dev?
Well I dont see why it couldnt be defined in libmircookie-dev. I think *if* we keep libmircookie-dev we should move the MirCookie into it (unless Im missing something for why this isnt possible). If we move to libmircommon-dev then we'll keep it :).
Need to talk with RAOF about it as well
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2927
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2928
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2929
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2928
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2931
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
+class CookieFactory
...
Should delete copy constructor and assignment.
~~~~
+ static unsigned const minimum_
1. Ought to be public, so that it can be accessed by client code.
2. Not providing the value in the header allows it to be changed without breaking ABI, but it would probably be more convenient for users to have the value visible.
~~~~
+ * Contruction function used to create a CookieFactory. The secret size must be
+ * greater then minimum_secret_size otherwise an expection will be thrown
...
+ * Contruction function used to create a CookieFactory as well as a secret.
+ * The secret size must be greater then minimum_secret_size otherwise an expection will be thrown
s/greater then/no less than/
~~~~
+/**
+* Checks entropy exists on the system, then fills in a vector with random numbers
+* up to size.
+*
+* \param [in] size The number of random numbers to generate.
+* \return A filled in vector with random numbers up to size
+*/
+std::vector<
Not needed in the API
~~~~
+unsigned const min_secret_size{8};
This isn't needed, minimum_secret_size should be initialized directly.
~~~~~
+namespace
+{
+ unsigned const secret_size{64};
+}
There ought to be a guarantee (e.g. a static assert) that this is greater than CookieFactory:
~~~~
+TEST(MirCookie
+{
+ std::vector<
+ EXPECT_THROW({
+ auto factory = mir::cookie:
+ }, std::logic_error);
+}
OK, but it is better to test the "off by one" case. I.e. CookieFactory:
~~~~
There are missing tests:
1. create(unsigned secret_size, std::vector<
This should be tested to check that a secret of the right size is saved, and that it throws if too small a size is requested.
2. get_random_
*If* this is in the API there should be corresponding tests.
~~~~
+MIR_COOKIE_1 {
+ global:
+ extern "C++" {
+ mir::cookie:
+ mir::cookie:
+ mir::cookie:
+ mir::cookie:
+ mir::cookie:
+ mir::cookie:
+ };
+ local: *;
+};
The only functions that need to be exported are mir::cookie:
Alan Griffiths (alan-griffiths) wrote : | # |
Just a bit of musing, not anything that requires action:
The create functions could be:
std::unique_
std::unique_
That might be more convenient for code that doesn't care about the secret size. There could also be other variants:
std::unique_
Which would support user code that just does:
auto const cf = CookieFactory:
Maybe not an important use case?
~~~~
It could also be convenient to include a definition of Secret:
using Secret = std::vector<
and use that in both the interface and user code.
Alan Griffiths (alan-griffiths) wrote : | # |
+TEST(MirCookie
+{
+ uint64_t timestamp = 23;
+ unsigned secret_size = 64;
+ std::vector<
+
+ auto factory = mir::cookie:
+ auto cookie = factory-
+
+ EXPECT_
+}
Not unreasonable, but I was actually thinking of...
uint64_t timestamp = 23;
unsigned secret_size = 64;
std:
auto const source_factory = mir::cookie:
auto const sink_factory = mir::cookie:
auto cookie = source_
EXPECT_
Which as one of the use cases we intend to support is something we should be testing.
Alan Griffiths (alan-griffiths) wrote : | # |
For me, this is the remaining blocker:
> > > > Is libmircookie really something that will need to be released in sync
> > with
> > > > every Mir release? Or should it be a separate project?
> > >
> > > I dont have a clear answer for this one. I just imagine since the project
> is
> > > pretty small it makes it easier to keep it in lp:mir atm? Will have to
> poke
> > > raof about that one.
> >
> > A further thought, the header is dependent on MirCookie (introduced here
> into
> > include/
> > dependent on libmircommon-dev.
> >
> > As we're introducing this dependency on mircommon, could we just put the
> code
> > into libmircommon and not a separate library?
> >
> > Or should MirCookie be defined in libmircookie-dev and not libmircommon-dev?
>
> Well I dont see why it couldnt be defined in libmircookie-dev. I think *if* we
> keep libmircookie-dev we should move the MirCookie into it (unless Im missing
> something for why this isnt possible). If we move to libmircommon-dev then
> we'll keep it :).
>
> Need to talk with RAOF about it as well
Alan Griffiths (alan-griffiths) wrote : | # |
It would be good for cookie clients to have a narrow, stable API.
To which end we should keep libmircookie as a separate project and make it independent of libmircommon-dev.
Brandon Schaefer (brandontschaefer) wrote : | # |
> It would be good for cookie clients to have a narrow, stable API.
>
> To which end we should keep libmircookie as a separate project and make it
> independent of libmircommon-dev.
Done. Is it fine to keep the entire mir cookie project inside lp:mir or should a new project be created?
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2932
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
On Wednesday, 16 September 2015 20:47:24 BST, Brandon Schaefer wrote:
>> It would be good for cookie clients to have a narrow, stable API.
>>
>> To which end we should keep libmircookie as a separate project
>> and make it
>> independent of libmircommon-dev.
>
> Done. Is it fine to keep the entire mir cookie project inside
> lp:mir or should a new project be created?
Fine in mir tree. (For now anyway)
--
Alan Griffiths. +44 (0)798 9938 758
Octopull Limited. http://
Brandon Schaefer (brandontschaefer) wrote : | # |
Hmm the only issue im not 100% sure about now. Is how we are going to expose the MirCookie to the mir_toolkit C api. I suppose Ill need to create a C api for the CookieFactory just to hold the MirCookie?
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2934
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2935
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2936
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
Pushed trivial fixes:
1. src/CMakeLists.txt to build cookie independently of any other Mir code
2. include/
3. include/
Alan Griffiths (alan-griffiths) wrote : | # |
NB I think the server API needs extending to retrieve the generated secret, but that can come in the next MP.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2942
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
+ static std::unique_
+ unsigned secret_size = 2 * minimum_
+ static std::unique_
http://
not too flummoxed by that, the rest lgtm
Alexandros Frantzis (afrantzis) wrote : | # |
Looks good.
Not blocking, but I find the following API simpler to understand:
create_
create_
Secret secret();
Of course, with this API the secret is no longer really "secret" (i.e. internal to the class), but I don't think it matters. If one has access to the class, then it doesn't really matter if one also has the secret (for our use cases at least).
Andreas Pokorny (andreas-pokorny) wrote : | # |
Overall looks good for me.
This has changed quite a bit since the last time. When do we need override_
nit :+ 470 braces of lambda functor..
Brandon Schaefer (brandontschaefer) wrote : | # |
> Looks good.
>
> Not blocking, but I find the following API simpler to understand:
>
> create_
> create_
> Secret secret();
>
> Of course, with this API the secret is no longer really "secret" (i.e.
> internal to the class), but I don't think it matters. If one has access to the
> class, then it doesn't really matter if one also has the secret (for our use
> cases at least).
A main use of the API is to share the secret around once its been created. So we need to be able to expose the secret on creation so we can share it with another factory.
Brandon Schaefer (brandontschaefer) wrote : | # |
LGTM
Brandon Schaefer (brandontschaefer) wrote : | # |
> Overall looks good for me.
>
> This has changed quite a bit since the last time. When do we need
> override_
>
This will be used in the client side of things. Not a perfect split from server/client but it will be used :).
> nit :+ 470 braces of lambda functor..
Tyler Hicks (tyhicks) wrote : | # |
Hello - A review from the security team was requested and I've started to look at the code. However, I feel like I'm missing a lot of context from the greater design. It seems like this is only the very low-level building blocks needed by the greater design.
1) Does any documentation exist on the design? Thomas spoke with us about potential high-level designs months ago and I roughly understand which direction you all chose but this HMAC design was not one that we discussed at that time.
2) How will content-hub register itself with Mir? What's the flow of cookies between Mir, the foreground app, and content-hub during copy and paste events?
3) What prevents malicious apps from attempting to brute force cookies? I don't see any type of penalty implementation for repeated, bad guesses. Is content-hub expected to implement that?
Chris Halse Rogers (raof) wrote : | # |
1) The copy/paste doc is at https:/
2) The design is for content-hub to share a secret with Mir, and each construct their own instance of CookieFactory from that secret. Content-hub does not need to register itself with Mir. The copy/paste doc has some cookie flow examples.
3) The Mir calls which accept a MirCookie¹ will disconnect any client that submits an invalid cookie. Content-hub should probably do the same. Would it be better to (a) document that any attestation failure should be fatal to the client, and (b) rename “bool attest_
¹: Here's an example: https:/
Tyler Hicks (tyhicks) wrote : | # |
1) Thanks! The copy/paste doc helps a lot but it lacks implementation details. For example, "secret" isn't mentioned anywhere in the document. It does get me closer to understanding the design.
2) I'm confused by the "Content-hub does not need to register itself with Mir" bit since content-hub must share a secret with Mir and then Mir's CookieFactory is constructed from that secret. How does Mir know that the CookieFactory that it constructed was done so with a secret from Content-hub and not some other process?
3) If Mir disconnects a client that submits an invalid cookie, what prevents the client from reconnecting and submitting another invalid cookie?
- Documenting that any attestation failure should be fatal to the client would be a good thing as long as a reconnecting is expensive.
- IIUC, assert_timestamp() is in the address space of the client, correct? If so, throwing an exception on failure would do no good because a malicious client could link against a modified library that doesn't throw an exception.
Chris Halse Rogers (raof) wrote : | # |
1, 2) Yeah, that bit of the design is unspecified. I was assuming that we'd either go for:
a) A parent process of unity8 and content-hub generates a secret and fd-passes it to both, or
b) Unity8 and content-hub share a file readable only by them, or
c) content-hub is started by unity8 and gets the secret fd-passed to it.
I'm not sufficiently familiar with the global design to know which one is most appropriate.
3) Unity8 only allows one connection per client. Actually, that's a lie; Unity8 effectively allows any client to connect to it, but in *theory* Unity8 only allows one connection per client. In theory, unity8 only allows applications started by upstart-app-launch and only allows one connection per launch, but in practice it allows anything that has --desktop-
So reconnection *should* be expensive, but currently isn't.
assert_timestamp() is in the server's address space; the secret required to assert a timestamp isn't available in the client address space.
Tyler Hicks (tyhicks) wrote : | # |
1, 2) Ok, I'll follow up with tvoss on that aspect of the design.
3) We could probably do something as simple as adding a penalty delay after each failed attest attempt, before disconnecting the client.
Note that I also included a couple inline questions.
Chris Halse Rogers (raof) wrote : | # |
3) It'd be reasonably complex to add a penalty delay after a failed attest attempt, but possible. It's much simpler for us to just disconnect the client.
Replies inline.
Tyler Hicks (tyhicks) wrote : | # |
Left some inline replies/comments.
Tyler Hicks (tyhicks) wrote : | # |
One more inline comment...
Chris Halse Rogers (raof) wrote : | # |
Replies also inline.
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-08-12 09:52:57 +0000 |
3 | +++ CMakeLists.txt 2015-09-17 09:09:28 +0000 |
4 | @@ -175,6 +175,7 @@ |
5 | find_package(LTTngUST REQUIRED) |
6 | pkg_check_modules(UDEV REQUIRED libudev) |
7 | pkg_check_modules(GLIB REQUIRED glib-2.0) |
8 | +pkg_check_modules(NETTLE REQUIRED nettle) |
9 | pkg_check_modules(UUID REQUIRED uuid) |
10 | |
11 | include_directories (${GLESv2_INCLUDE_DIRS}) |
12 | |
13 | === modified file 'cmake/ABICheck.cmake' |
14 | --- cmake/ABICheck.cmake 2015-07-23 02:39:20 +0000 |
15 | +++ cmake/ABICheck.cmake 2015-09-17 09:09:28 +0000 |
16 | @@ -79,6 +79,7 @@ |
17 | make_lib_descriptor(client) |
18 | make_lib_descriptor(server) |
19 | make_lib_descriptor(common INCLUDE_PRIVATE EXCLUDE_HEADERS ${mircommon-exclude-headers}) |
20 | +make_lib_descriptor(cookie) |
21 | make_lib_descriptor(platform INCLUDE_PRIVATE EXCLUDE_HEADERS ${mirplatform-exclude-headers}) |
22 | if(MIR_BUILD_PLATFORM_MESA_KMS) |
23 | make_lib_descriptor(clientplatformmesa LIBRARY_HEADER ${CMAKE_SOURCE_DIR}/src/include/client/mir/client_platform_factory.h) |
24 | @@ -124,7 +125,7 @@ |
25 | ) |
26 | endmacro(_define_abi_check_for) |
27 | |
28 | -set(the_libs mirserver mirclient mircommon mirplatform) |
29 | +set(the_libs mirserver mirclient mircommon mirplatform mircookie) |
30 | if(MIR_BUILD_PLATFORM_MESA_KMS) |
31 | set(the_libs ${the_libs} mirclientplatformmesa mirplatformgraphicsmesakms) |
32 | endif() |
33 | |
34 | === modified file 'debian/control' |
35 | --- debian/control 2015-09-15 12:37:25 +0000 |
36 | +++ debian/control 2015-09-17 09:09:28 +0000 |
37 | @@ -43,6 +43,7 @@ |
38 | uuid-dev, |
39 | python3:any, |
40 | dh-python, |
41 | + nettle-dev, |
42 | Standards-Version: 3.9.4 |
43 | Homepage: https://launchpad.net/mir |
44 | # If you aren't a member of ~mir-team but need to upload packaging changes, |
45 | @@ -402,6 +403,33 @@ |
46 | This package depends on a full set of graphics drivers for running Mir on top |
47 | of an existing Android driver stack. |
48 | |
49 | +Package: libmircookie1 |
50 | +Section: libs |
51 | +Architecture: any |
52 | +Multi-Arch: same |
53 | +Pre-Depends: ${misc:Pre-Depends} |
54 | +Depends: ${misc:Depends}, |
55 | +Description: Produce and verify spoof-resistant timestamps - runtime library |
56 | + libmircookie provides a simple mechanism for a group of cooperating processes |
57 | + to hand out and verify difficult-to-forge timestamps to untrusted 3rd parties. |
58 | + . |
59 | + This package contains the runtime library for generating and verifying the |
60 | + attestable timestamps. |
61 | + |
62 | +Package: libmircookie-dev |
63 | +Section: libdevel |
64 | +Architecture: any |
65 | +Multi-Arch: same |
66 | +Pre-Depends: ${misc:Pre-Depends} |
67 | +Depends: libmircookie1 (= ${binary:Version}), |
68 | + ${misc:Depends}, |
69 | +Description: Produce and verify spoof-resistant timestamps - development headers |
70 | + libmircookie provides a simple mechanism for a group of cooperating processes |
71 | + to hand out and verify difficult-to-forge timestamps to untrusted 3rd parties. |
72 | + . |
73 | + This package contains the development headers for building programs that |
74 | + generate or verify the attestable timestamps. |
75 | + |
76 | Package: python3-mir-perf-framework |
77 | Section: python |
78 | Architecture: all |
79 | |
80 | === added file 'debian/libmircookie-dev.install' |
81 | --- debian/libmircookie-dev.install 1970-01-01 00:00:00 +0000 |
82 | +++ debian/libmircookie-dev.install 2015-09-17 09:09:28 +0000 |
83 | @@ -0,0 +1,3 @@ |
84 | +/usr/include/mircookie/ |
85 | +/usr/lib/*/libmircookie.so |
86 | +/usr/lib/*/pkgconfig/mircookie.pc |
87 | |
88 | === added file 'debian/libmircookie1.install' |
89 | --- debian/libmircookie1.install 1970-01-01 00:00:00 +0000 |
90 | +++ debian/libmircookie1.install 2015-09-17 09:09:28 +0000 |
91 | @@ -0,0 +1,1 @@ |
92 | +/usr/lib/*/libmircookie.so.1 |
93 | |
94 | === modified file 'debian/mir-test-tools.install' |
95 | --- debian/mir-test-tools.install 2015-06-23 08:00:53 +0000 |
96 | +++ debian/mir-test-tools.install 2015-09-17 09:09:28 +0000 |
97 | @@ -10,3 +10,4 @@ |
98 | usr/lib/*/mir/server-platform/graphics-dummy.so |
99 | usr/lib/*/mir/server-platform/input-stub.so |
100 | usr/lib/*/mir/client-platform/dummy.so |
101 | +usr/share/udev_recordings |
102 | |
103 | === added directory 'include/cookie' |
104 | === added directory 'include/cookie/mir' |
105 | === added file 'include/cookie/mir/cookie_factory.h' |
106 | --- include/cookie/mir/cookie_factory.h 1970-01-01 00:00:00 +0000 |
107 | +++ include/cookie/mir/cookie_factory.h 2015-09-17 09:09:28 +0000 |
108 | @@ -0,0 +1,104 @@ |
109 | +/* |
110 | + * Copyright © 2015 Canonical Ltd. |
111 | + * |
112 | + * This program is free software: you can redistribute it and/or modify |
113 | + * it under the terms of the GNU General Public License version 3 as |
114 | + * published by the Free Software Foundation. |
115 | + * |
116 | + * This program is distributed in the hope that it will be useful, |
117 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
118 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
119 | + * GNU General Public License for more details. |
120 | + * |
121 | + * You should have received a copy of the GNU General Public License |
122 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
123 | + * |
124 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
125 | + */ |
126 | + |
127 | +#ifndef MIR_COOKIE_COOKIE_FACTORY_H_ |
128 | +#define MIR_COOKIE_COOKIE_FACTORY_H_ |
129 | + |
130 | +#include "mir_toolkit/cookie.h" |
131 | + |
132 | +#include <vector> |
133 | +#include <memory> |
134 | + |
135 | +namespace mir |
136 | +{ |
137 | +namespace cookie |
138 | +{ |
139 | +using Secret = std::vector<uint8_t>; |
140 | + |
141 | +/** |
142 | + * \brief A source of moderately-difficult-to-spoof cookies. |
143 | + * |
144 | + * The primary motivation for this is to provide event timestamps that clients find it difficult to spoof. |
145 | + * This is useful for focus grant and similar operations where shell behaviour should be dependent on |
146 | + * the timestamp of the client event that caused the request. |
147 | + * |
148 | + * Some spoofing protection is desirable; experience with X clients shows that they will go to some effort |
149 | + * to attempt to bypass focus stealing prevention. |
150 | + * |
151 | + */ |
152 | +class CookieFactory |
153 | +{ |
154 | +public: |
155 | + /** |
156 | + * Contruction function used to create a CookieFactory. The secret size must be |
157 | + * no less then minimum_secret_size otherwise an expection will be thrown |
158 | + * |
159 | + * \param [in] secret A filled in secret used to set the key for the hash function |
160 | + * \return A unique_ptr CookieFactory |
161 | + */ |
162 | + static std::unique_ptr<CookieFactory> create_from_secret(Secret const& secret); |
163 | + |
164 | + /** |
165 | + * Contruction function used to create a CookieFactory as well as a secret. |
166 | + * The secret size must be no less then minimum_secret_size otherwise an expection will be thrown |
167 | + * |
168 | + * \param [in] secret_size The size of the secret to create, must be larger then minimum_secret_size |
169 | + * \param [out] save_secret The secret that was created. |
170 | + * \return A unique_ptr CookieFactory |
171 | + */ |
172 | + static std::unique_ptr<CookieFactory> create_saving_secret(Secret& save_secret, |
173 | + unsigned secret_size = 2 * minimum_secret_size); |
174 | + |
175 | + /** |
176 | + * Contruction function used to create a CookieFactory and a secret which it keeps internally. |
177 | + * The secret size must be no less then minimum_secret_size otherwise an expection will be thrown |
178 | + * |
179 | + * \param [in] secret_size The size of the secret to create, must be larger then minimum_secret_size |
180 | + * \return A unique_ptr CookieFactory |
181 | + */ |
182 | + static std::unique_ptr<CookieFactory> create_keeping_secret(unsigned secret_size = 2 * minimum_secret_size); |
183 | + |
184 | + CookieFactory(CookieFactory const& factory) = delete; |
185 | + CookieFactory& operator=(CookieFactory const& factory) = delete; |
186 | + virtual ~CookieFactory() noexcept = default; |
187 | + |
188 | + /** |
189 | + * Turns a timestamp into a MAC and returns a MirCookie. |
190 | + * |
191 | + * \param [in] timestamp The timestamp |
192 | + * \return MirCookie with the stored MAC and timestamp |
193 | + */ |
194 | + virtual MirCookie timestamp_to_cookie(uint64_t const& timestamp) = 0; |
195 | + |
196 | + /** |
197 | + * Checks that a MirCookie is a valid MirCookie. |
198 | + * |
199 | + * \param [in] cookie A created MirCookie |
200 | + * \return True when the MirCookie is valid, False when the MirCookie is not valid |
201 | + */ |
202 | + virtual bool attest_timestamp(MirCookie const& cookie) = 0; |
203 | + |
204 | + static unsigned const minimum_secret_size = 8; |
205 | + |
206 | +protected: |
207 | + CookieFactory() = default; |
208 | +}; |
209 | + |
210 | +} |
211 | +} |
212 | +#endif // MIR_COOKIE_COOKIE_FACTORY_H_ |
213 | |
214 | === added directory 'include/cookie/mir_toolkit' |
215 | === added file 'include/cookie/mir_toolkit/cookie.h' |
216 | --- include/cookie/mir_toolkit/cookie.h 1970-01-01 00:00:00 +0000 |
217 | +++ include/cookie/mir_toolkit/cookie.h 2015-09-17 09:09:28 +0000 |
218 | @@ -0,0 +1,44 @@ |
219 | +/* |
220 | + * Copyright © 2015 Canonical Ltd. |
221 | + * |
222 | + * This program is free software: you can redistribute it and/or modify |
223 | + * it under the terms of the GNU General Public License version 3 as |
224 | + * published by the Free Software Foundation. |
225 | + * |
226 | + * This program is distributed in the hope that it will be useful, |
227 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
228 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
229 | + * GNU General Public License for more details. |
230 | + * |
231 | + * You should have received a copy of the GNU General Public License |
232 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
233 | + * |
234 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
235 | + */ |
236 | + |
237 | +#ifndef MIR_TOOLKIT_COOKIE_FACTORY_H_ |
238 | +#define MIR_TOOLKIT_COOKIE_FACTORY_H_ |
239 | + |
240 | +#include <stdint.h> |
241 | + |
242 | +/** |
243 | + * \addtogroup mir_toolkit |
244 | + * @{ |
245 | + */ |
246 | +/* This is C code. Not C++. */ |
247 | +#ifdef __cplusplus |
248 | +extern "C" { |
249 | +#endif |
250 | + |
251 | +typedef struct MirCookie |
252 | +{ |
253 | + uint64_t timestamp; |
254 | + uint64_t mac; |
255 | +} MirCookie; |
256 | + |
257 | +#ifdef __cplusplus |
258 | +} |
259 | +#endif |
260 | +/**@}*/ |
261 | + |
262 | +#endif // MIR_TOOLKIT_COOKIE_FACTORY_H_ |
263 | |
264 | === modified file 'include/server/mir/server.h' |
265 | --- include/server/mir/server.h 2015-09-08 03:25:06 +0000 |
266 | +++ include/server/mir/server.h 2015-09-17 09:09:28 +0000 |
267 | @@ -34,6 +34,10 @@ |
268 | namespace input { class CompositeEventFilter; class InputDispatcher; class CursorListener; class TouchVisualizer; class InputDeviceHub;} |
269 | namespace logging { class Logger; } |
270 | namespace options { class Option; } |
271 | +namespace cookie |
272 | +{ |
273 | +using Secret = std::vector<uint8_t>; |
274 | +} |
275 | namespace shell |
276 | { |
277 | class DisplayLayout; |
278 | @@ -79,6 +83,13 @@ |
279 | /// This must remain valid while apply_settings() and run() are called. |
280 | void set_command_line(int argc, char const* argv[]); |
281 | |
282 | + /// creates the CookieFactory from the given secret |
283 | + /// This secret is used to generate timestamps that can be attested to by |
284 | + /// libmircookie. Any process this secret is shared with can verify Mir-generated |
285 | + /// cookies, or produce their own. |
286 | + /// \note If not explicitly set, a random secret will be chosen. |
287 | + void override_the_cookie_factory(mir::cookie::Secret const& secret); |
288 | + |
289 | /// Applies any configuration options, hooks, or custom implementations. |
290 | /// Must be called before calling run() or accessing any mir subsystems. |
291 | void apply_settings(); |
292 | @@ -381,6 +392,7 @@ |
293 | /// using the format "fd://%d". |
294 | auto open_prompt_socket() -> Fd; |
295 | /** @} */ |
296 | + |
297 | private: |
298 | struct ServerConfiguration; |
299 | struct Self; |
300 | |
301 | === modified file 'include/test/mir_test_framework/executable_path.h' |
302 | --- include/test/mir_test_framework/executable_path.h 2015-06-22 03:04:56 +0000 |
303 | +++ include/test/mir_test_framework/executable_path.h 2015-09-17 09:09:28 +0000 |
304 | @@ -26,6 +26,7 @@ |
305 | std::string executable_path(); |
306 | |
307 | std::string library_path(); |
308 | +std::string udev_recordings_path(); |
309 | std::string server_platform(std::string const& name); |
310 | std::string client_platform(std::string const& name); |
311 | } |
312 | |
313 | === modified file 'src/CMakeLists.txt' |
314 | --- src/CMakeLists.txt 2015-09-07 11:54:56 +0000 |
315 | +++ src/CMakeLists.txt 2015-09-17 09:09:28 +0000 |
316 | @@ -1,6 +1,9 @@ |
317 | # We need MIRPLATFORM_ABI in both libmirplatform and the platform implementations. |
318 | set(MIRPLATFORM_ABI 10) |
319 | |
320 | +# Add the cookie implementation before exposing any APIs |
321 | +add_subdirectory(cookie/) |
322 | + |
323 | # We need MIR_CLIENT_PLATFORM_PATH in both libmirclient and the platform |
324 | # implementations |
325 | set(MIR_CLIENT_PLATFORM_PATH |
326 | |
327 | === added directory 'src/cookie' |
328 | === added file 'src/cookie/CMakeLists.txt' |
329 | --- src/cookie/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
330 | +++ src/cookie/CMakeLists.txt 2015-09-17 09:09:28 +0000 |
331 | @@ -0,0 +1,48 @@ |
332 | +set(PREFIX "${CMAKE_INSTALL_PREFIX}") |
333 | +set(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}") |
334 | +set(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}") |
335 | +set(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include") |
336 | + |
337 | +configure_file( |
338 | + ${CMAKE_CURRENT_SOURCE_DIR}/mircookie.pc.in |
339 | + ${CMAKE_CURRENT_BINARY_DIR}/mircookie.pc |
340 | + @ONLY |
341 | +) |
342 | + |
343 | +include_directories( |
344 | + ${PROJECT_SOURCE_DIR}/include/cookie |
345 | + ${NETTLE_INCLUDE_DIRS} |
346 | +) |
347 | + |
348 | +set(MIRCOOKIE_ABI 1) |
349 | +set(symbol_map ${CMAKE_SOURCE_DIR}/src/cookie/symbols.map) |
350 | + |
351 | +add_library(mircookie SHARED |
352 | + |
353 | + cookie_factory.cpp |
354 | +) |
355 | + |
356 | +set_target_properties(mircookie |
357 | + PROPERTIES |
358 | + SOVERSION ${MIRCOOKIE_ABI} |
359 | + LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}" |
360 | +) |
361 | + |
362 | +target_link_libraries(mircookie |
363 | + ${NETTLE_LDFLAGS} ${NETTLE_LIBS} |
364 | +) |
365 | + |
366 | +install( |
367 | + TARGETS mircookie |
368 | + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} |
369 | + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) |
370 | + |
371 | +install( |
372 | + DIRECTORY ${CMAKE_SOURCE_DIR}/include/cookie/mir |
373 | + DESTINATION "include/mircookie" |
374 | +) |
375 | + |
376 | +install( |
377 | + FILES ${CMAKE_CURRENT_BINARY_DIR}/mircookie.pc |
378 | + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig |
379 | +) |
380 | |
381 | === added file 'src/cookie/cookie_factory.cpp' |
382 | --- src/cookie/cookie_factory.cpp 1970-01-01 00:00:00 +0000 |
383 | +++ src/cookie/cookie_factory.cpp 2015-09-17 09:09:28 +0000 |
384 | @@ -0,0 +1,161 @@ |
385 | +/* |
386 | + * Copyright © 2015 Canonical Ltd. |
387 | + * |
388 | + * This program is free software: you can redistribute it and/or modify |
389 | + * it under the terms of the GNU General Public License version 3 as |
390 | + * published by the Free Software Foundation. |
391 | + * |
392 | + * This program is distributed in the hope that it will be useful, |
393 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
394 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
395 | + * GNU General Public License for more details. |
396 | + * |
397 | + * You should have received a copy of the GNU General Public License |
398 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
399 | + * |
400 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
401 | + */ |
402 | + |
403 | +#include "mir/cookie_factory.h" |
404 | + |
405 | +#include <algorithm> |
406 | +#include <random> |
407 | +#include <memory> |
408 | +#include <system_error> |
409 | + |
410 | +#include <nettle/hmac.h> |
411 | +#include <linux/random.h> |
412 | +#include <sys/types.h> |
413 | +#include <sys/stat.h> |
414 | +#include <fcntl.h> |
415 | +#include <sys/select.h> |
416 | + |
417 | +#include <boost/throw_exception.hpp> |
418 | + |
419 | +namespace |
420 | +{ |
421 | +std::string const random_device_path{"/dev/random"}; |
422 | +std::string const urandom_device_path{"/dev/urandom"}; |
423 | +int const wait_seconds{30}; |
424 | +} |
425 | + |
426 | +static mir::cookie::Secret get_random_data(unsigned size) |
427 | +{ |
428 | + mir::cookie::Secret buffer(size); |
429 | + int random_fd; |
430 | + int retval; |
431 | + fd_set rfds; |
432 | + |
433 | + struct timeval tv; |
434 | + tv.tv_sec = wait_seconds; |
435 | + tv.tv_usec = 0; |
436 | + |
437 | + if ((random_fd = open(random_device_path.c_str(), O_RDONLY)) == -1) |
438 | + { |
439 | + int error = errno; |
440 | + BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(), |
441 | + "open failed on device " + random_device_path)); |
442 | + } |
443 | + |
444 | + FD_ZERO(&rfds); |
445 | + FD_SET(random_fd, &rfds); |
446 | + |
447 | + /* We want to block until *some* entropy exists on boot, then use urandom once we have some */ |
448 | + retval = select(random_fd + 1, &rfds, NULL, NULL, &tv); |
449 | + |
450 | + /* We are done with /dev/random at this point, and it is either an error or ready to be read */ |
451 | + if (close(random_fd) == -1) |
452 | + { |
453 | + int error = errno; |
454 | + BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(), |
455 | + "close failed on device " + random_device_path)); |
456 | + } |
457 | + |
458 | + if (retval == -1) |
459 | + { |
460 | + int error = errno; |
461 | + BOOST_THROW_EXCEPTION(std::system_error(error, std::system_category(), |
462 | + "select failed on file descriptor " + std::to_string(random_fd) + |
463 | + " from device " + random_device_path)); |
464 | + } |
465 | + else if (retval && FD_ISSET(random_fd, &rfds)) |
466 | + { |
467 | + std::uniform_int_distribution<uint8_t> dist; |
468 | + std::random_device rand_dev(urandom_device_path); |
469 | + |
470 | + std::generate(std::begin(buffer), std::end(buffer), [&]() { |
471 | + return dist(rand_dev); |
472 | + }); |
473 | + } |
474 | + else |
475 | + { |
476 | + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to read from device: " + random_device_path + |
477 | + " after: " + std::to_string(wait_seconds) + " seconds")); |
478 | + } |
479 | + |
480 | + return buffer; |
481 | +} |
482 | + |
483 | +class CookieFactoryNettle : public mir::cookie::CookieFactory |
484 | +{ |
485 | +public: |
486 | + CookieFactoryNettle(mir::cookie::Secret const& secret) |
487 | + { |
488 | + if (secret.size() < minimum_secret_size) |
489 | + BOOST_THROW_EXCEPTION(std::logic_error("Secret size " + std::to_string(secret.size()) + " is to small, require " + |
490 | + std::to_string(minimum_secret_size) + " or greater.")); |
491 | + |
492 | + hmac_sha1_set_key(&ctx, secret.size(), secret.data()); |
493 | + } |
494 | + |
495 | + virtual ~CookieFactoryNettle() noexcept = default; |
496 | + |
497 | + MirCookie timestamp_to_cookie(uint64_t const& timestamp) override |
498 | + { |
499 | + MirCookie cookie { timestamp, 0 }; |
500 | + calculate_mac(cookie); |
501 | + return cookie; |
502 | + } |
503 | + |
504 | + bool attest_timestamp(MirCookie const& cookie) override |
505 | + { |
506 | + return verify_mac(cookie); |
507 | + } |
508 | + |
509 | +private: |
510 | + void calculate_mac(MirCookie& cookie) |
511 | + { |
512 | + hmac_sha1_update(&ctx, sizeof(cookie.timestamp), reinterpret_cast<uint8_t*>(&cookie.timestamp)); |
513 | + hmac_sha1_digest(&ctx, sizeof(cookie.mac), reinterpret_cast<uint8_t*>(&cookie.mac)); |
514 | + } |
515 | + |
516 | + bool verify_mac(MirCookie const& cookie) |
517 | + { |
518 | + decltype(cookie.mac) calculated_mac; |
519 | + uint8_t* message = reinterpret_cast<uint8_t*>(const_cast<decltype(cookie.timestamp)*>(&cookie.timestamp)); |
520 | + hmac_sha1_update(&ctx, sizeof(cookie.timestamp), message); |
521 | + hmac_sha1_digest(&ctx, sizeof(calculated_mac), reinterpret_cast<uint8_t*>(&calculated_mac)); |
522 | + |
523 | + return calculated_mac == cookie.mac; |
524 | + } |
525 | + |
526 | + struct hmac_sha1_ctx ctx; |
527 | +}; |
528 | + |
529 | +std::unique_ptr<mir::cookie::CookieFactory> mir::cookie::CookieFactory::create_from_secret(mir::cookie::Secret const& secret) |
530 | +{ |
531 | + return std::make_unique<CookieFactoryNettle>(secret); |
532 | +} |
533 | + |
534 | +std::unique_ptr<mir::cookie::CookieFactory> mir::cookie::CookieFactory::create_saving_secret(mir::cookie::Secret& save_secret, |
535 | + unsigned secret_size) |
536 | +{ |
537 | + save_secret = get_random_data(secret_size); |
538 | + return std::make_unique<CookieFactoryNettle>(save_secret); |
539 | +} |
540 | + |
541 | +std::unique_ptr<mir::cookie::CookieFactory> mir::cookie::CookieFactory::create_keeping_secret(unsigned secret_size) |
542 | +{ |
543 | + auto secret = get_random_data(secret_size); |
544 | + return std::make_unique<CookieFactoryNettle>(secret); |
545 | +} |
546 | |
547 | === added file 'src/cookie/mircookie.pc.in' |
548 | --- src/cookie/mircookie.pc.in 1970-01-01 00:00:00 +0000 |
549 | +++ src/cookie/mircookie.pc.in 2015-09-17 09:09:28 +0000 |
550 | @@ -0,0 +1,11 @@ |
551 | +prefix=@PREFIX@ |
552 | +exec_prefix=@EXEC_PREFIX@ |
553 | +libdir=@LIBDIR@ |
554 | +includedir=@INCLUDEDIR@/mircookie |
555 | + |
556 | +Name: mircookie |
557 | +Description: Mir client library |
558 | +Version: @MIR_VERSION@ |
559 | +Requires.private: nettle |
560 | +Libs: -L${libdir} -lmircookie |
561 | +Cflags: -I${includedir} |
562 | |
563 | === added file 'src/cookie/symbols.map' |
564 | --- src/cookie/symbols.map 1970-01-01 00:00:00 +0000 |
565 | +++ src/cookie/symbols.map 2015-09-17 09:09:28 +0000 |
566 | @@ -0,0 +1,9 @@ |
567 | +MIR_COOKIE_1 { |
568 | + global: |
569 | + extern "C++" { |
570 | + mir::cookie::CookieFactory::create_from_secret*; |
571 | + mir::cookie::CookieFactory::create_saving_secret*; |
572 | + mir::cookie::CookieFactory::create_keeping_secret*; |
573 | + }; |
574 | + local: *; |
575 | +}; |
576 | |
577 | === modified file 'src/include/server/mir/default_server_configuration.h' |
578 | --- src/include/server/mir/default_server_configuration.h 2015-09-08 03:25:06 +0000 |
579 | +++ src/include/server/mir/default_server_configuration.h 2015-09-17 09:09:28 +0000 |
580 | @@ -41,6 +41,10 @@ |
581 | class SharedLibrary; |
582 | class SharedLibraryProberReport; |
583 | |
584 | +namespace cookie |
585 | +{ |
586 | +class CookieFactory; |
587 | +} |
588 | namespace dispatch |
589 | { |
590 | class MultiplexingDispatchable; |
591 | @@ -186,7 +190,8 @@ |
592 | std::shared_ptr<DisplayChanger> the_display_changer() override; |
593 | std::shared_ptr<graphics::Platform> the_graphics_platform() override; |
594 | std::shared_ptr<input::InputDispatcher> the_input_dispatcher() override; |
595 | - std::shared_ptr<EmergencyCleanup> the_emergency_cleanup() override; |
596 | + std::shared_ptr<EmergencyCleanup> the_emergency_cleanup() override; |
597 | + std::shared_ptr<cookie::CookieFactory> the_cookie_factory() override; |
598 | /** |
599 | * Function to call when a "fatal" error occurs. This implementation allows |
600 | * the default strategy to be overridden by --on-fatal-error-abort to force a |
601 | @@ -441,6 +446,7 @@ |
602 | CachedPtr<SharedLibraryProberReport> shared_library_prober_report; |
603 | CachedPtr<shell::Shell> shell; |
604 | CachedPtr<scene::ApplicationNotRespondingDetector> application_not_responding_detector; |
605 | + CachedPtr<cookie::CookieFactory> cookie_factory; |
606 | |
607 | private: |
608 | std::shared_ptr<options::Configuration> const configuration_options; |
609 | |
610 | === modified file 'src/include/server/mir/server_configuration.h' |
611 | --- src/include/server/mir/server_configuration.h 2015-06-18 04:38:28 +0000 |
612 | +++ src/include/server/mir/server_configuration.h 2015-09-17 09:09:28 +0000 |
613 | @@ -22,6 +22,10 @@ |
614 | |
615 | namespace mir |
616 | { |
617 | +namespace cookie |
618 | +{ |
619 | +class CookieFactory; |
620 | +} |
621 | namespace compositor |
622 | { |
623 | class Compositor; |
624 | @@ -75,6 +79,7 @@ |
625 | virtual std::shared_ptr<DisplayChanger> the_display_changer() = 0; |
626 | virtual std::shared_ptr<graphics::Platform> the_graphics_platform() = 0; |
627 | virtual std::shared_ptr<EmergencyCleanup> the_emergency_cleanup() = 0; |
628 | + virtual std::shared_ptr<cookie::CookieFactory> the_cookie_factory() = 0; |
629 | virtual auto the_fatal_error_strategy() -> void (*)(char const* reason, ...) = 0; |
630 | virtual std::shared_ptr<scene::ApplicationNotRespondingDetector> the_application_not_responding_detector() = 0; |
631 | |
632 | |
633 | === modified file 'src/server/CMakeLists.txt' |
634 | --- src/server/CMakeLists.txt 2015-09-07 11:54:56 +0000 |
635 | +++ src/server/CMakeLists.txt 2015-09-17 09:09:28 +0000 |
636 | @@ -10,6 +10,7 @@ |
637 | ${PROJECT_SOURCE_DIR}/src/include/platform |
638 | ${PROJECT_SOURCE_DIR}/src/include/client |
639 | ${PROJECT_SOURCE_DIR}/src/include/server |
640 | + ${PROJECT_SOURCE_DIR}/include/cookie |
641 | ${GLIB_INCLUDE_DIRS} |
642 | ) |
643 | add_definitions(-DMIR_SERVER_INPUT_PLATFORM_VERSION="${MIR_SERVER_INPUT_PLATFORM_VERSION}") |
644 | @@ -95,7 +96,7 @@ |
645 | mirplatform |
646 | mircommon |
647 | mirprotobuf |
648 | - |
649 | + mircookie |
650 | xcursorloader-static |
651 | |
652 | ${GLog_LIBRARY} |
653 | |
654 | === modified file 'src/server/default_server_configuration.cpp' |
655 | --- src/server/default_server_configuration.cpp 2015-06-17 05:20:42 +0000 |
656 | +++ src/server/default_server_configuration.cpp 2015-09-17 09:09:28 +0000 |
657 | @@ -1,5 +1,5 @@ |
658 | /* |
659 | - * Copyright © 2012-2014 Canonical Ltd. |
660 | + * Copyright © 2012-2015 Canonical Ltd. |
661 | * |
662 | * This program is free software: you can redistribute it and/or modify it |
663 | * under the terms of the GNU General Public License version 3, |
664 | @@ -24,6 +24,7 @@ |
665 | #include "mir/default_server_status_listener.h" |
666 | #include "mir/emergency_cleanup.h" |
667 | #include "mir/default_configuration.h" |
668 | +#include "mir/cookie_factory.h" |
669 | |
670 | #include "mir/logging/dumb_console_logger.h" |
671 | #include "mir/options/program_option.h" |
672 | @@ -41,6 +42,8 @@ |
673 | #include "mir/scene/null_prompt_session_listener.h" |
674 | #include "default_emergency_cleanup.h" |
675 | |
676 | +#include <type_traits> |
677 | + |
678 | namespace mc = mir::compositor; |
679 | namespace geom = mir::geometry; |
680 | namespace mf = mir::frontend; |
681 | @@ -51,6 +54,11 @@ |
682 | namespace msh = mir::shell; |
683 | namespace mi = mir::input; |
684 | |
685 | +namespace |
686 | +{ |
687 | + unsigned const secret_size{64}; |
688 | +} |
689 | + |
690 | mir::DefaultServerConfiguration::DefaultServerConfiguration(int argc, char const* argv[]) : |
691 | DefaultServerConfiguration(std::make_shared<mo::DefaultConfiguration>(argc, argv)) |
692 | { |
693 | @@ -173,6 +181,18 @@ |
694 | }); |
695 | } |
696 | |
697 | +std::shared_ptr<mir::cookie::CookieFactory> mir::DefaultServerConfiguration::the_cookie_factory() |
698 | +{ |
699 | + return cookie_factory( |
700 | + []() |
701 | + { |
702 | + static_assert(secret_size >= mir::cookie::CookieFactory::minimum_secret_size, |
703 | + "Secret size is smaller then the minimum secret size"); |
704 | + |
705 | + return mir::cookie::CookieFactory::create_keeping_secret(secret_size); |
706 | + }); |
707 | +} |
708 | + |
709 | auto mir::DefaultServerConfiguration::the_fatal_error_strategy() |
710 | -> void (*)(char const* reason, ...) |
711 | { |
712 | |
713 | === modified file 'src/server/server.cpp' |
714 | --- src/server/server.cpp 2015-09-08 03:25:06 +0000 |
715 | +++ src/server/server.cpp 2015-09-17 09:09:28 +0000 |
716 | @@ -29,6 +29,7 @@ |
717 | #include "mir/main_loop.h" |
718 | #include "mir/report_exception.h" |
719 | #include "mir/run_mir.h" |
720 | +#include "mir/cookie_factory.h" |
721 | |
722 | // TODO these are used to frig a stub renderer when running headless |
723 | #include "mir/compositor/renderer.h" |
724 | @@ -101,6 +102,7 @@ |
725 | std::weak_ptr<options::Option> options; |
726 | std::string config_file; |
727 | std::shared_ptr<ServerConfiguration> server_config; |
728 | + std::shared_ptr<cookie::CookieFactory> cookie_factory; |
729 | |
730 | std::function<void()> init_callback{[]{}}; |
731 | int argc{0}; |
732 | @@ -207,6 +209,15 @@ |
733 | return mir::DefaultServerConfiguration::the_renderer_factory(); |
734 | } |
735 | |
736 | + auto the_cookie_factory() -> std::shared_ptr<cookie::CookieFactory> override |
737 | + { |
738 | + if (self->cookie_factory) |
739 | + { |
740 | + return self->cookie_factory; |
741 | + } |
742 | + return mir::DefaultServerConfiguration::the_cookie_factory(); |
743 | + } |
744 | + |
745 | using mir::DefaultServerConfiguration::the_options; |
746 | |
747 | FOREACH_OVERRIDE(MIR_SERVER_CONFIG_OVERRIDE) |
748 | @@ -277,6 +288,12 @@ |
749 | self->argv = argv; |
750 | } |
751 | |
752 | +void mir::Server::override_the_cookie_factory(mir::cookie::Secret const& secret) |
753 | +{ |
754 | + verify_setting_allowed(self->server_config); |
755 | + self->cookie_factory = mir::cookie::CookieFactory::create_from_secret(secret); |
756 | +} |
757 | + |
758 | void mir::Server::add_init_callback(std::function<void()> const& init_callback) |
759 | { |
760 | auto const& existing = self->init_callback; |
761 | |
762 | === modified file 'src/server/symbols.map' |
763 | --- src/server/symbols.map 2015-09-11 12:29:40 +0000 |
764 | +++ src/server/symbols.map 2015-09-17 09:09:28 +0000 |
765 | @@ -135,6 +135,7 @@ |
766 | mir::ServerActionQueue::?ServerActionQueue*; |
767 | mir::ServerActionQueue::ServerActionQueue*; |
768 | mir::Server::add_configuration_option*; |
769 | + mir::Server::override_the_cookie_factory*; |
770 | mir::Server::add_emergency_cleanup*; |
771 | mir::Server::add_init_callback*; |
772 | mir::Server::apply_settings*; |
773 | @@ -590,6 +591,7 @@ |
774 | mir::DefaultServerConfiguration::the_buffer_stream_factory*; |
775 | mir::DefaultServerConfiguration::the_clock*; |
776 | mir::DefaultServerConfiguration::the_composite_event_filter*; |
777 | + mir::DefaultServerConfiguration::the_cookie_factory*; |
778 | mir::DefaultServerConfiguration::the_event_filter_chain_dispatcher*; |
779 | mir::DefaultServerConfiguration::the_surface_input_dispatcher; |
780 | mir::DefaultServerConfiguration::the_compositor*; |
781 | |
782 | === modified file 'tests/acceptance-tests/CMakeLists.txt' |
783 | --- tests/acceptance-tests/CMakeLists.txt 2015-09-09 18:59:38 +0000 |
784 | +++ tests/acceptance-tests/CMakeLists.txt 2015-09-17 09:09:28 +0000 |
785 | @@ -2,6 +2,8 @@ |
786 | |
787 | include_directories( |
788 | ${CMAKE_SOURCE_DIR} |
789 | + ${PROJECT_SOURCE_DIR}/include/cookie |
790 | + ${UMOCKDEV_INCLUDE_DIRS} |
791 | ) |
792 | |
793 | set( |
794 | @@ -80,6 +82,7 @@ |
795 | mirclient-debug-extension |
796 | mirserver |
797 | |
798 | + ${UMOCKDEV_LIBRARIES} |
799 | ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. |
800 | ) |
801 | |
802 | |
803 | === modified file 'tests/include/mir_test_framework/udev_environment.h' |
804 | --- tests/include/mir_test_framework/udev_environment.h 2015-02-22 07:46:25 +0000 |
805 | +++ tests/include/mir_test_framework/udev_environment.h 2015-09-17 09:09:28 +0000 |
806 | @@ -53,6 +53,32 @@ |
807 | */ |
808 | void add_standard_device(std::string const& name); |
809 | |
810 | + /** |
811 | + * Load an ioctl recording for a UMockdev device |
812 | + * |
813 | + * Looks for a <tt>name</tt>.ioctl file recorded with umockdev-record --ioctl |
814 | + * and adds it to the associated device in the testbed. |
815 | + * |
816 | + * The udev records for the device these ioctl records will be associated with |
817 | + * must already exist in the testbed |
818 | + * |
819 | + * @param name The unadorned filename for the ioctl records to add |
820 | + */ |
821 | + void load_device_ioctls(std::string const& name); |
822 | + |
823 | + /** |
824 | + * Load an evemu evdev recording for a UMockdev device |
825 | + * |
826 | + * Looks for a <tt>name</tt>.evemu file recorded with umockdev-record --evemu |
827 | + * (or evemu-record) and associates it with the udev device it was recorded from. |
828 | + * |
829 | + * The udev records for the device this recording is associated with |
830 | + * must already exist in the testbed |
831 | + * |
832 | + * @param name The unadorned filename for the ioctl records to add |
833 | + */ |
834 | + void load_device_evemu(std::string const& name); |
835 | + |
836 | UMockdevTestbed *testbed; |
837 | std::string const recordings_path; |
838 | }; |
839 | |
840 | === modified file 'tests/integration-tests/CMakeLists.txt' |
841 | --- tests/integration-tests/CMakeLists.txt 2015-09-09 18:59:38 +0000 |
842 | +++ tests/integration-tests/CMakeLists.txt 2015-09-17 09:09:28 +0000 |
843 | @@ -4,6 +4,7 @@ |
844 | ${CMAKE_SOURCE_DIR} |
845 | ${PROTOBUF_INCLUDE_DIRS} |
846 | ${CMAKE_CURRENT_BINARY_DIR} |
847 | + ${PROJECT_SOURCE_DIR}/include/cookie |
848 | ${PROJECT_SOURCE_DIR}/src/include/platform |
849 | ${PROJECT_SOURCE_DIR}/src/include/common |
850 | ${PROJECT_SOURCE_DIR}/src/include/server |
851 | |
852 | === modified file 'tests/mir_test_framework/CMakeLists.txt' |
853 | --- tests/mir_test_framework/CMakeLists.txt 2015-09-14 17:04:48 +0000 |
854 | +++ tests/mir_test_framework/CMakeLists.txt 2015-09-17 09:09:28 +0000 |
855 | @@ -16,6 +16,8 @@ |
856 | -DMIR_SERVER_PLATFORM_PATH="${MIR_SERVER_PLATFORM_PATH}" |
857 | -DMIR_CLIENT_PLATFORM_ABI_STRING="${MIR_CLIENT_PLATFORM_ABI}" |
858 | -DMIR_SERVER_GRAPHICS_PLATFORM_ABI_STRING="${MIR_SERVER_GRAPHICS_PLATFORM_ABI}" |
859 | + -DMIR_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}" |
860 | + -DMIR_BUILD_PREFIX="${CMAKE_BINARY_DIR}" |
861 | ) |
862 | |
863 | add_library(mir-public-test-framework OBJECT |
864 | @@ -161,3 +163,5 @@ |
865 | install(TARGETS mirplatformgraphicsstub LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH}) |
866 | |
867 | install(TARGETS mirclientplatformstub LIBRARY DESTINATION ${MIR_CLIENT_PLATFORM_PATH}) |
868 | + |
869 | +add_subdirectory(udev_recordings/) |
870 | |
871 | === modified file 'tests/mir_test_framework/executable_path.cpp' |
872 | --- tests/mir_test_framework/executable_path.cpp 2015-06-17 05:20:42 +0000 |
873 | +++ tests/mir_test_framework/executable_path.cpp 2015-09-17 09:09:28 +0000 |
874 | @@ -45,6 +45,19 @@ |
875 | return executable_path() + "/../lib"; |
876 | } |
877 | |
878 | +std::string mir_test_framework::udev_recordings_path() |
879 | +{ |
880 | + std::string run_path = executable_path() + "/udev_recordings"; |
881 | + std::string install_path = MIR_INSTALL_PREFIX"/share/udev_recordings"; |
882 | + |
883 | + if (boost::filesystem::exists(run_path)) |
884 | + return run_path; |
885 | + else if (boost::filesystem::exists(install_path)) |
886 | + return install_path; |
887 | + |
888 | + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to find udev_recordings in standard search locations")); |
889 | +} |
890 | + |
891 | std::string mir_test_framework::server_platform(std::string const& name) |
892 | { |
893 | std::string libname{name}; |
894 | |
895 | === modified file 'tests/mir_test_framework/udev_environment.cpp' |
896 | --- tests/mir_test_framework/udev_environment.cpp 2015-02-22 07:46:25 +0000 |
897 | +++ tests/mir_test_framework/udev_environment.cpp 2015-09-17 09:09:28 +0000 |
898 | @@ -38,7 +38,7 @@ |
899 | namespace mtf = mir_test_framework; |
900 | |
901 | mtf::UdevEnvironment::UdevEnvironment() |
902 | - : recordings_path(mtf::executable_path() + "/udev_recordings") |
903 | + : recordings_path(mtf::udev_recordings_path()) |
904 | { |
905 | testbed = umockdev_testbed_new(); |
906 | } |
907 | @@ -109,4 +109,41 @@ |
908 | } |
909 | } |
910 | } |
911 | + |
912 | + auto script_filename = recordings_path + "/" + name + ".script"; |
913 | + if (stat(script_filename.c_str(), &sb) == 0) |
914 | + { |
915 | + if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) |
916 | + { |
917 | + if (!umockdev_testbed_load_script(testbed, NULL, script_filename.c_str(), &err)) |
918 | + { |
919 | + BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Failed to load device recording: ") + |
920 | + err->message)); |
921 | + } |
922 | + } |
923 | + } |
924 | +} |
925 | + |
926 | +void mtf::UdevEnvironment::load_device_ioctls(std::string const& name) |
927 | +{ |
928 | + auto ioctls_filename = recordings_path + "/" + name + ".ioctl"; |
929 | + |
930 | + GError* err = nullptr; |
931 | + if (!umockdev_testbed_load_ioctl(testbed, NULL, ioctls_filename.c_str(), &err)) |
932 | + { |
933 | + BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Failed to load ioctl recording: ") + |
934 | + err->message)); |
935 | + } |
936 | +} |
937 | + |
938 | +void mtf::UdevEnvironment::load_device_evemu(std::string const& name) |
939 | +{ |
940 | + auto evemu_filename = recordings_path + "/" + name + ".evemu"; |
941 | + |
942 | + GError* err = nullptr; |
943 | + if (!umockdev_testbed_load_evemu_events(testbed, NULL, evemu_filename.c_str(), &err)) |
944 | + { |
945 | + BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Failed to load evemu recording: ") + |
946 | + err->message)); |
947 | + } |
948 | } |
949 | |
950 | === added file 'tests/mir_test_framework/udev_recordings/CMakeLists.txt' |
951 | --- tests/mir_test_framework/udev_recordings/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
952 | +++ tests/mir_test_framework/udev_recordings/CMakeLists.txt 2015-09-17 09:09:28 +0000 |
953 | @@ -0,0 +1,3 @@ |
954 | +file(GLOB UDEV_FILES *.umockdev *.ioctl *.evemu) |
955 | + |
956 | +install(FILES ${UDEV_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/udev_recordings) |
957 | |
958 | === added file 'tests/mir_test_framework/udev_recordings/laptop-keyboard-hello.evemu' |
959 | --- tests/mir_test_framework/udev_recordings/laptop-keyboard-hello.evemu 1970-01-01 00:00:00 +0000 |
960 | +++ tests/mir_test_framework/udev_recordings/laptop-keyboard-hello.evemu 2015-09-17 09:09:28 +0000 |
961 | @@ -0,0 +1,272 @@ |
962 | +# device /dev/input/event4 |
963 | +# EVEMU 1.2 |
964 | +# Input device name: "AT Translated Set 2 keyboard" |
965 | +# Input device ID: bus 0x11 vendor 0x01 product 0x01 version 0xab83 |
966 | +# Supported events: |
967 | +# Event type 0 (EV_SYN) |
968 | +# Event code 0 (SYN_REPORT) |
969 | +# Event code 1 (SYN_CONFIG) |
970 | +# Event code 4 (FF_STATUS_STOPPED) |
971 | +# Event code 17 ((null)) |
972 | +# Event code 20 ((null)) |
973 | +# Event type 1 (EV_KEY) |
974 | +# Event code 1 (KEY_ESC) |
975 | +# Event code 2 (KEY_1) |
976 | +# Event code 3 (KEY_2) |
977 | +# Event code 4 (KEY_3) |
978 | +# Event code 5 (KEY_4) |
979 | +# Event code 6 (KEY_5) |
980 | +# Event code 7 (KEY_6) |
981 | +# Event code 8 (KEY_7) |
982 | +# Event code 9 (KEY_8) |
983 | +# Event code 10 (KEY_9) |
984 | +# Event code 11 (KEY_0) |
985 | +# Event code 12 (KEY_MINUS) |
986 | +# Event code 13 (KEY_EQUAL) |
987 | +# Event code 14 (KEY_BACKSPACE) |
988 | +# Event code 15 (KEY_TAB) |
989 | +# Event code 16 (KEY_Q) |
990 | +# Event code 17 (KEY_W) |
991 | +# Event code 18 (KEY_E) |
992 | +# Event code 19 (KEY_R) |
993 | +# Event code 20 (KEY_T) |
994 | +# Event code 21 (KEY_Y) |
995 | +# Event code 22 (KEY_U) |
996 | +# Event code 23 (KEY_I) |
997 | +# Event code 24 (KEY_O) |
998 | +# Event code 25 (KEY_P) |
999 | +# Event code 26 (KEY_LEFTBRACE) |
1000 | +# Event code 27 (KEY_RIGHTBRACE) |
1001 | +# Event code 28 (KEY_ENTER) |
1002 | +# Event code 29 (KEY_LEFTCTRL) |
1003 | +# Event code 30 (KEY_A) |
1004 | +# Event code 31 (KEY_S) |
1005 | +# Event code 32 (KEY_D) |
1006 | +# Event code 33 (KEY_F) |
1007 | +# Event code 34 (KEY_G) |
1008 | +# Event code 35 (KEY_H) |
1009 | +# Event code 36 (KEY_J) |
1010 | +# Event code 37 (KEY_K) |
1011 | +# Event code 38 (KEY_L) |
1012 | +# Event code 39 (KEY_SEMICOLON) |
1013 | +# Event code 40 (KEY_APOSTROPHE) |
1014 | +# Event code 41 (KEY_GRAVE) |
1015 | +# Event code 42 (KEY_LEFTSHIFT) |
1016 | +# Event code 43 (KEY_BACKSLASH) |
1017 | +# Event code 44 (KEY_Z) |
1018 | +# Event code 45 (KEY_X) |
1019 | +# Event code 46 (KEY_C) |
1020 | +# Event code 47 (KEY_V) |
1021 | +# Event code 48 (KEY_B) |
1022 | +# Event code 49 (KEY_N) |
1023 | +# Event code 50 (KEY_M) |
1024 | +# Event code 51 (KEY_COMMA) |
1025 | +# Event code 52 (KEY_DOT) |
1026 | +# Event code 53 (KEY_SLASH) |
1027 | +# Event code 54 (KEY_RIGHTSHIFT) |
1028 | +# Event code 55 (KEY_KPASTERISK) |
1029 | +# Event code 56 (KEY_LEFTALT) |
1030 | +# Event code 57 (KEY_SPACE) |
1031 | +# Event code 58 (KEY_CAPSLOCK) |
1032 | +# Event code 59 (KEY_F1) |
1033 | +# Event code 60 (KEY_F2) |
1034 | +# Event code 61 (KEY_F3) |
1035 | +# Event code 62 (KEY_F4) |
1036 | +# Event code 63 (KEY_F5) |
1037 | +# Event code 64 (KEY_F6) |
1038 | +# Event code 65 (KEY_F7) |
1039 | +# Event code 66 (KEY_F8) |
1040 | +# Event code 67 (KEY_F9) |
1041 | +# Event code 68 (KEY_F10) |
1042 | +# Event code 69 (KEY_NUMLOCK) |
1043 | +# Event code 70 (KEY_SCROLLLOCK) |
1044 | +# Event code 71 (KEY_KP7) |
1045 | +# Event code 72 (KEY_KP8) |
1046 | +# Event code 73 (KEY_KP9) |
1047 | +# Event code 74 (KEY_KPMINUS) |
1048 | +# Event code 75 (KEY_KP4) |
1049 | +# Event code 76 (KEY_KP5) |
1050 | +# Event code 77 (KEY_KP6) |
1051 | +# Event code 78 (KEY_KPPLUS) |
1052 | +# Event code 79 (KEY_KP1) |
1053 | +# Event code 80 (KEY_KP2) |
1054 | +# Event code 81 (KEY_KP3) |
1055 | +# Event code 82 (KEY_KP0) |
1056 | +# Event code 83 (KEY_KPDOT) |
1057 | +# Event code 85 (KEY_ZENKAKUHANKAKU) |
1058 | +# Event code 86 (KEY_102ND) |
1059 | +# Event code 87 (KEY_F11) |
1060 | +# Event code 88 (KEY_F12) |
1061 | +# Event code 89 (KEY_RO) |
1062 | +# Event code 90 (KEY_KATAKANA) |
1063 | +# Event code 91 (KEY_HIRAGANA) |
1064 | +# Event code 92 (KEY_HENKAN) |
1065 | +# Event code 93 (KEY_KATAKANAHIRAGANA) |
1066 | +# Event code 94 (KEY_MUHENKAN) |
1067 | +# Event code 95 (KEY_KPJPCOMMA) |
1068 | +# Event code 96 (KEY_KPENTER) |
1069 | +# Event code 97 (KEY_RIGHTCTRL) |
1070 | +# Event code 98 (KEY_KPSLASH) |
1071 | +# Event code 99 (KEY_SYSRQ) |
1072 | +# Event code 100 (KEY_RIGHTALT) |
1073 | +# Event code 102 (KEY_HOME) |
1074 | +# Event code 103 (KEY_UP) |
1075 | +# Event code 104 (KEY_PAGEUP) |
1076 | +# Event code 105 (KEY_LEFT) |
1077 | +# Event code 106 (KEY_RIGHT) |
1078 | +# Event code 107 (KEY_END) |
1079 | +# Event code 108 (KEY_DOWN) |
1080 | +# Event code 109 (KEY_PAGEDOWN) |
1081 | +# Event code 110 (KEY_INSERT) |
1082 | +# Event code 111 (KEY_DELETE) |
1083 | +# Event code 112 (KEY_MACRO) |
1084 | +# Event code 113 (KEY_MUTE) |
1085 | +# Event code 114 (KEY_VOLUMEDOWN) |
1086 | +# Event code 115 (KEY_VOLUMEUP) |
1087 | +# Event code 116 (KEY_POWER) |
1088 | +# Event code 117 (KEY_KPEQUAL) |
1089 | +# Event code 118 (KEY_KPPLUSMINUS) |
1090 | +# Event code 119 (KEY_PAUSE) |
1091 | +# Event code 121 (KEY_KPCOMMA) |
1092 | +# Event code 122 (KEY_HANGEUL) |
1093 | +# Event code 123 (KEY_HANJA) |
1094 | +# Event code 124 (KEY_YEN) |
1095 | +# Event code 125 (KEY_LEFTMETA) |
1096 | +# Event code 126 (KEY_RIGHTMETA) |
1097 | +# Event code 127 (KEY_COMPOSE) |
1098 | +# Event code 128 (KEY_STOP) |
1099 | +# Event code 140 (KEY_CALC) |
1100 | +# Event code 142 (KEY_SLEEP) |
1101 | +# Event code 143 (KEY_WAKEUP) |
1102 | +# Event code 155 (KEY_MAIL) |
1103 | +# Event code 156 (KEY_BOOKMARKS) |
1104 | +# Event code 157 (KEY_COMPUTER) |
1105 | +# Event code 158 (KEY_BACK) |
1106 | +# Event code 159 (KEY_FORWARD) |
1107 | +# Event code 163 (KEY_NEXTSONG) |
1108 | +# Event code 164 (KEY_PLAYPAUSE) |
1109 | +# Event code 165 (KEY_PREVIOUSSONG) |
1110 | +# Event code 166 (KEY_STOPCD) |
1111 | +# Event code 172 (KEY_HOMEPAGE) |
1112 | +# Event code 173 (KEY_REFRESH) |
1113 | +# Event code 183 (KEY_F13) |
1114 | +# Event code 184 (KEY_F14) |
1115 | +# Event code 185 (KEY_F15) |
1116 | +# Event code 217 (KEY_SEARCH) |
1117 | +# Event code 226 (KEY_MEDIA) |
1118 | +# Event type 4 (EV_MSC) |
1119 | +# Event code 4 (MSC_SCAN) |
1120 | +# Event type 17 (EV_LED) |
1121 | +# Event code 0 (LED_NUML) |
1122 | +# Event code 1 (LED_CAPSL) |
1123 | +# Event code 2 (LED_SCROLLL) |
1124 | +# Event type 20 (EV_REP) |
1125 | +# Properties: |
1126 | +# N: AT Translated Set 2 keyboard |
1127 | +# I: 0011 0001 0001 ab83 |
1128 | +# P: 00 00 00 00 00 00 00 00 |
1129 | +# B: 00 13 00 12 00 00 00 00 00 |
1130 | +# B: 01 fe ff ff ff ff ff ff ff |
1131 | +# B: 01 ff ff ef ff df ff ff fe |
1132 | +# B: 01 01 d0 00 f8 78 30 80 03 |
1133 | +# B: 01 00 00 00 02 04 00 00 00 |
1134 | +# B: 01 00 00 00 00 00 00 00 00 |
1135 | +# B: 01 00 00 00 00 00 00 00 00 |
1136 | +# B: 01 00 00 00 00 00 00 00 00 |
1137 | +# B: 01 00 00 00 00 00 00 00 00 |
1138 | +# B: 01 00 00 00 00 00 00 00 00 |
1139 | +# B: 01 00 00 00 00 00 00 00 00 |
1140 | +# B: 01 00 00 00 00 00 00 00 00 |
1141 | +# B: 01 00 00 00 00 00 00 00 00 |
1142 | +# B: 02 00 00 00 00 00 00 00 00 |
1143 | +# B: 03 00 00 00 00 00 00 00 00 |
1144 | +# B: 04 10 00 00 00 00 00 00 00 |
1145 | +# B: 05 00 00 00 00 00 00 00 00 |
1146 | +# B: 11 07 00 00 00 00 00 00 00 |
1147 | +# B: 12 00 00 00 00 00 00 00 00 |
1148 | +# B: 15 00 00 00 00 00 00 00 00 |
1149 | +# B: 15 00 00 00 00 00 00 00 00 |
1150 | +################################ |
1151 | +# Waiting for events # |
1152 | +################################ |
1153 | +E: 0.000000 0004 0004 0028 # EV_MSC / MSC_SCAN 28 |
1154 | +E: 0.000000 0001 001c 0000 # EV_KEY / KEY_ENTER 0 |
1155 | +E: 0.000000 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1156 | +E: 0.825945 0004 0004 0054 # EV_MSC / MSC_SCAN 54 |
1157 | +E: 0.825945 0001 0036 0001 # EV_KEY / KEY_RIGHTSHIFT 1 |
1158 | +E: 0.825945 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1159 | +E: 1.101404 0004 0004 0054 # EV_MSC / MSC_SCAN 54 |
1160 | +E: 1.101404 0001 0036 0002 # EV_KEY / KEY_RIGHTSHIFT 2 |
1161 | +E: 1.101404 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1162 | +E: 1.131449 0004 0004 0054 # EV_MSC / MSC_SCAN 54 |
1163 | +E: 1.131449 0001 0036 0002 # EV_KEY / KEY_RIGHTSHIFT 2 |
1164 | +E: 1.131449 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1165 | +E: 1.161472 0004 0004 0036 # EV_MSC / MSC_SCAN 36 |
1166 | +E: 1.161472 0001 0024 0001 # EV_KEY / KEY_J 1 |
1167 | +E: 1.161472 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1168 | +E: 1.221981 0004 0004 0036 # EV_MSC / MSC_SCAN 36 |
1169 | +E: 1.221981 0001 0024 0000 # EV_KEY / KEY_J 0 |
1170 | +E: 1.221981 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1171 | +E: 1.241906 0004 0004 0054 # EV_MSC / MSC_SCAN 54 |
1172 | +E: 1.241906 0001 0036 0000 # EV_KEY / KEY_RIGHTSHIFT 0 |
1173 | +E: 1.241906 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1174 | +E: 1.346773 0004 0004 0032 # EV_MSC / MSC_SCAN 32 |
1175 | +E: 1.346773 0001 0020 0001 # EV_KEY / KEY_D 1 |
1176 | +E: 1.346773 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1177 | +E: 1.432213 0004 0004 0032 # EV_MSC / MSC_SCAN 32 |
1178 | +E: 1.432213 0001 0020 0000 # EV_KEY / KEY_D 0 |
1179 | +E: 1.432213 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1180 | +E: 1.562060 0004 0004 0025 # EV_MSC / MSC_SCAN 25 |
1181 | +E: 1.562060 0001 0019 0001 # EV_KEY / KEY_P 1 |
1182 | +E: 1.562060 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1183 | +E: 1.622477 0004 0004 0025 # EV_MSC / MSC_SCAN 25 |
1184 | +E: 1.622477 0001 0019 0000 # EV_KEY / KEY_P 0 |
1185 | +E: 1.622477 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1186 | +E: 1.687305 0004 0004 0025 # EV_MSC / MSC_SCAN 25 |
1187 | +E: 1.687305 0001 0019 0001 # EV_KEY / KEY_P 1 |
1188 | +E: 1.687305 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1189 | +E: 1.777807 0004 0004 0025 # EV_MSC / MSC_SCAN 25 |
1190 | +E: 1.777807 0001 0019 0000 # EV_KEY / KEY_P 0 |
1191 | +E: 1.777807 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1192 | +E: 1.867577 0004 0004 0031 # EV_MSC / MSC_SCAN 31 |
1193 | +E: 1.867577 0001 001f 0001 # EV_KEY / KEY_S 1 |
1194 | +E: 1.867577 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1195 | +E: 1.953019 0004 0004 0031 # EV_MSC / MSC_SCAN 31 |
1196 | +E: 1.953019 0001 001f 0000 # EV_KEY / KEY_S 0 |
1197 | +E: 1.953019 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1198 | +E: 2.118004 0004 0004 0054 # EV_MSC / MSC_SCAN 54 |
1199 | +E: 2.118004 0001 0036 0001 # EV_KEY / KEY_RIGHTSHIFT 1 |
1200 | +E: 2.118004 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1201 | +E: 2.348316 0004 0004 0002 # EV_MSC / MSC_SCAN 2 |
1202 | +E: 2.348316 0001 0002 0001 # EV_KEY / KEY_1 1 |
1203 | +E: 2.348316 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1204 | +E: 2.489561 0004 0004 0002 # EV_MSC / MSC_SCAN 2 |
1205 | +E: 2.489561 0001 0002 0000 # EV_KEY / KEY_1 0 |
1206 | +E: 2.489561 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1207 | +E: 2.523740 0004 0004 0054 # EV_MSC / MSC_SCAN 54 |
1208 | +E: 2.523740 0001 0036 0000 # EV_KEY / KEY_RIGHTSHIFT 0 |
1209 | +E: 2.523740 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1210 | +E: 6.714286 0004 0004 0029 # EV_MSC / MSC_SCAN 29 |
1211 | +E: 6.714286 0001 001d 0001 # EV_KEY / KEY_LEFTCTRL 1 |
1212 | +E: 6.714286 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1213 | +E: 6.989728 0004 0004 0029 # EV_MSC / MSC_SCAN 29 |
1214 | +E: 6.989728 0001 001d 0002 # EV_KEY / KEY_LEFTCTRL 2 |
1215 | +E: 6.989728 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1216 | +E: 7.019767 0004 0004 0029 # EV_MSC / MSC_SCAN 29 |
1217 | +E: 7.019767 0001 001d 0002 # EV_KEY / KEY_LEFTCTRL 2 |
1218 | +E: 7.019767 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1219 | +E: 7.049847 0004 0004 0029 # EV_MSC / MSC_SCAN 29 |
1220 | +E: 7.049847 0001 001d 0002 # EV_KEY / KEY_LEFTCTRL 2 |
1221 | +E: 7.049847 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1222 | +E: 7.079889 0004 0004 0029 # EV_MSC / MSC_SCAN 29 |
1223 | +E: 7.079889 0001 001d 0002 # EV_KEY / KEY_LEFTCTRL 2 |
1224 | +E: 7.079889 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1225 | +E: 7.109934 0004 0004 0029 # EV_MSC / MSC_SCAN 29 |
1226 | +E: 7.109934 0001 001d 0002 # EV_KEY / KEY_LEFTCTRL 2 |
1227 | +E: 7.109934 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1228 | +E: 7.139943 0004 0004 0029 # EV_MSC / MSC_SCAN 29 |
1229 | +E: 7.139943 0001 001d 0002 # EV_KEY / KEY_LEFTCTRL 2 |
1230 | +E: 7.139943 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1231 | +E: 7.170005 0004 0004 0023 # EV_MSC / MSC_SCAN 23 |
1232 | +E: 7.170005 0001 0017 0001 # EV_KEY / KEY_I 1 |
1233 | +E: 7.170005 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- |
1234 | |
1235 | === modified file 'tests/unit-tests/CMakeLists.txt' |
1236 | --- tests/unit-tests/CMakeLists.txt 2015-09-07 11:54:56 +0000 |
1237 | +++ tests/unit-tests/CMakeLists.txt 2015-09-17 09:09:28 +0000 |
1238 | @@ -25,6 +25,7 @@ |
1239 | ${GBM_INCLUDE_DIRS} |
1240 | ${UMOCKDEV_INCLUDE_DIRS} |
1241 | |
1242 | + ${PROJECT_SOURCE_DIR}/include/cookie |
1243 | ${PROJECT_SOURCE_DIR}/src/include/platform |
1244 | ${PROJECT_SOURCE_DIR}/src/include/server |
1245 | ${PROJECT_SOURCE_DIR}/src/include/client |
1246 | @@ -67,6 +68,7 @@ |
1247 | test_shared_library_prober.cpp |
1248 | test_lockable_callback.cpp |
1249 | test_module_deleter.cpp |
1250 | + test_mir_cookie.cpp |
1251 | ) |
1252 | |
1253 | if (MIR_TEST_PLATFORM STREQUAL "mesa-x11") |
1254 | |
1255 | === added file 'tests/unit-tests/test_mir_cookie.cpp' |
1256 | --- tests/unit-tests/test_mir_cookie.cpp 1970-01-01 00:00:00 +0000 |
1257 | +++ tests/unit-tests/test_mir_cookie.cpp 2015-09-17 09:09:28 +0000 |
1258 | @@ -0,0 +1,105 @@ |
1259 | +/* |
1260 | + * Copyright © 2015 Canonical Ltd. |
1261 | + * |
1262 | + * This program is free software: you can redistribute it and/or modify |
1263 | + * it under the terms of the GNU General Public License version 3 as |
1264 | + * published by the Free Software Foundation. |
1265 | + * |
1266 | + * This program is distributed in the hope that it will be useful, |
1267 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1268 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1269 | + * GNU General Public License for more details. |
1270 | + * |
1271 | + * You should have received a copy of the GNU General Public License |
1272 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1273 | + * |
1274 | + * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> |
1275 | + */ |
1276 | + |
1277 | +#include "mir_toolkit/mir_client_library.h" |
1278 | +#include "mir/cookie_factory.h" |
1279 | + |
1280 | +#include "mir_test_framework/headless_test.h" |
1281 | +#include "mir_test_framework/connected_client_with_a_surface.h" |
1282 | +#include "mir/test/doubles/wrap_shell_to_track_latest_surface.h" |
1283 | +#include "mir/shell/shell_wrapper.h" |
1284 | +#include "mir/test/validity_matchers.h" |
1285 | +#include "mir/test/wait_condition.h" |
1286 | + |
1287 | +#include "boost/throw_exception.hpp" |
1288 | + |
1289 | +#include <gtest/gtest.h> |
1290 | + |
1291 | +namespace mtf = mir_test_framework; |
1292 | +namespace mtd = mir::test::doubles; |
1293 | +namespace msh = mir::shell; |
1294 | + |
1295 | +TEST(MirCookieFactory, attests_real_timestamp) |
1296 | +{ |
1297 | + std::vector<uint8_t> secret{ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xde, 0x01 }; |
1298 | + auto factory = mir::cookie::CookieFactory::create_from_secret(secret); |
1299 | + |
1300 | + uint64_t mock_timestamp{0x322322322332}; |
1301 | + |
1302 | + auto cookie = factory->timestamp_to_cookie(mock_timestamp); |
1303 | + |
1304 | + EXPECT_TRUE(factory->attest_timestamp(cookie)); |
1305 | +} |
1306 | + |
1307 | +TEST(MirCookieFactory, doesnt_attest_faked_timestamp) |
1308 | +{ |
1309 | + std::vector<uint8_t> secret{ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xde, 0x01 }; |
1310 | + auto factory = mir::cookie::CookieFactory::create_from_secret(secret); |
1311 | + |
1312 | + MirCookie bad_client_no_biscuit{ 0x33221100, 0x33221100 }; |
1313 | + |
1314 | + EXPECT_FALSE(factory->attest_timestamp(bad_client_no_biscuit)); |
1315 | +} |
1316 | + |
1317 | +TEST(MirCookieFactory, timestamp_trusted_with_different_secret_doesnt_attest) |
1318 | +{ |
1319 | + std::vector<uint8_t> alice{ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xde, 0x01 }; |
1320 | + std::vector<uint8_t> bob{ 0x01, 0x02, 0x44, 0xd8, 0xee, 0x0f, 0xde, 0x01 }; |
1321 | + |
1322 | + auto alices_factory = mir::cookie::CookieFactory::create_from_secret(alice); |
1323 | + auto bobs_factory = mir::cookie::CookieFactory::create_from_secret(bob); |
1324 | + |
1325 | + uint64_t mock_timestamp{0x01020304}; |
1326 | + |
1327 | + auto alices_cookie = alices_factory->timestamp_to_cookie(mock_timestamp); |
1328 | + auto bobs_cookie = bobs_factory->timestamp_to_cookie(mock_timestamp); |
1329 | + |
1330 | + EXPECT_FALSE(alices_factory->attest_timestamp(bobs_cookie)); |
1331 | + EXPECT_FALSE(bobs_factory->attest_timestamp(alices_cookie)); |
1332 | +} |
1333 | + |
1334 | +TEST(MirCookieFactory, throw_when_secret_size_to_small) |
1335 | +{ |
1336 | + std::vector<uint8_t> bob(mir::cookie::CookieFactory::minimum_secret_size - 1); |
1337 | + EXPECT_THROW({ |
1338 | + auto factory = mir::cookie::CookieFactory::create_from_secret(bob); |
1339 | + }, std::logic_error); |
1340 | +} |
1341 | + |
1342 | +TEST(MirCookieFactory, saves_a_secret) |
1343 | +{ |
1344 | + std::vector<uint8_t> secret; |
1345 | + unsigned secret_size = 64; |
1346 | + |
1347 | + mir::cookie::CookieFactory::create_saving_secret(secret, secret_size); |
1348 | + |
1349 | + EXPECT_EQ(secret.size(), secret_size); |
1350 | +} |
1351 | + |
1352 | +TEST(MirCookieFactory, timestamp_trusted_with_saved_secret_does_attest) |
1353 | +{ |
1354 | + uint64_t timestamp = 23; |
1355 | + unsigned secret_size = 64; |
1356 | + std::vector<uint8_t> secret; |
1357 | + |
1358 | + auto source_factory = mir::cookie::CookieFactory::create_saving_secret(secret, secret_size); |
1359 | + auto sink_factory = mir::cookie::CookieFactory::create_from_secret(secret); |
1360 | + auto cookie = source_factory->timestamp_to_cookie(timestamp); |
1361 | + |
1362 | + EXPECT_TRUE(sink_factory->attest_timestamp(cookie)); |
1363 | +} |
1364 | |
1365 | === modified file 'tools/update_package_abis.sh' |
1366 | --- tools/update_package_abis.sh 2015-08-07 05:46:34 +0000 |
1367 | +++ tools/update_package_abis.sh 2015-09-17 09:09:28 +0000 |
1368 | @@ -16,6 +16,7 @@ |
1369 | libmirplatform:MIRPLATFORM_ABI \ |
1370 | libmirprotobuf:MIRPROTOBUF_ABI \ |
1371 | libmirserver:MIRSERVER_ABI \ |
1372 | + libmircookie:MIRCOOKIE_ABI \ |
1373 | mir-client-platform-android:MIR_CLIENT_PLATFORM_ABI \ |
1374 | mir-client-platform-mesa:MIR_CLIENT_PLATFORM_ABI \ |
1375 | mir-platform-graphics-android:MIR_SERVER_GRAPHICS_PLATFORM_ABI \ |
FAILED: Continuous integration, rev:2909 jenkins. qa.ubuntu. com/job/ mir-ci/ 4825/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/3868/ console jenkins. qa.ubuntu. com/job/ mir-clang- vivid-amd64- build/2775/ console jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/3814/ console jenkins. qa.ubuntu. com/job/ mir-wily- amd64-ci/ 974/console jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 3814/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/4825/ rebuild
http://