[haiku-development] Design for signed packages

  • From: Jonathan Schleifer <js-haiku-development@xxxxxxxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Sat, 22 Mar 2014 22:28:53 +0100

I just send this as a reply to a thread in the haikuports-svn mailing list, but 
just after sending it, it occurred to me that it would be much better placed 
here. So, here goes:

Anfang der weitergeleiteten Nachricht:

> Von: Jonathan Schleifer <js-haikuports-commits@xxxxxxxxxxx>
> Betreff: Aw: [HaikuPorts-svn] haikuporter : 1 new changeset : a4ba368099a5
> Datum: 22. März 2014 22:24:28 MEZ
> An: HaikuPorts SVN commits <haikuports-svn@xxxxxxxxxxxxxxxxxxxxxxxxxxx>
> 
> I just had a better idea than doing it per-file:
> 
> So, if a package is activated, the signature is verified by the package 
> daemon. This is a one time operation and thus not time-critical. So nothing 
> to worry about here.
> 
> However, if we want to go the SecureBoot route, we'd need to let the loader 
> verify the kernel. At first this sounds like every hpkg needs to be verified, 
> but that's not the case.
> 
> First, let's assume we have an encrypted Haiku partition and an unencrypted 
> EFI boot partition. (I know we don't have Full Disk Encryption yet, but in 
> order for SecureBoot to make *any* sense, it would be necessary - otherwise 
> you could just place an unsigned binary somewhere where it gets executed. We 
> have Axel's TrueCrypt implementation already, so that'd be a good start).
> 
> So, in order to implement SecureBoot, we'd need a stage1 bootloader that is 
> signed with the Microsoft key that then loads the stage2 bootloader. The 
> stage2 bootloader is inside haiku_loader.hpkg, so only the signature for that 
> needs to be verified.
> 
> Remember our file system is encrypted. So now we need to ask the user for the 
> encryption password (in the loader, that is). The loader is already signed so 
> it cannot be tampered with. So after the user entered the correct password, 
> the loader can now load the haiku.hpkg - without checking the signature!
> 
> Why? Because we already did so when we installed it, and an adversary cannot 
> modify data on an encrypted partition.
> 
> So the only overhead is verifying the stage2 loader (EFI does that) and the 
> haiku_loader.hpkg (quite small). Thus I don't think there will be a 
> performance implication.
> 
> As we determined now that we don't need per-file signatures, here's how I 
> want to do it:
> 
> First, hash the following fields of the header:
>       uint32  magic;
>       uint16  header_size;
>       uint16  version;
>       uint64  total_size;
>       uint16  minor_version;
> 
>       uint64  heap_size_uncompressed;
> 
>       uint32  attributes_length;
>       uint32  attributes_strings_length;
>       uint32  attributes_strings_count;
>       uint32  reserved1;
> 
>       uint64  toc_length;
>       uint64  toc_strings_length;
>       uint64  toc_strings_count;
> 
> As you can see, I stripped out these 3:
>       uint16  heap_compression;
>       uint32  heap_chunk_size;
>       uint64  heap_size_compressed;
> 
> I'll explain in a minute why.
> 
> The next thing following is the heap - which is basically the rest of the 
> file. So the idea is do uncompress the heap and verify the uncompressed data. 
> As we did not hash the compression-related fields above, it means the 
> signature is still valid if you decide to recompress it with a different 
> algorithm!
> 
> Finally, at the end of the heap (we fortunately know it's compressed size so 
> we can easily seek there), I would add the following fields (not final yet, 
> but to give you a rough idea):
> 
>       uint8   signature[64];
>       uint16  certificateLength;
>       uint8   certificate[];
> 
> signature will be an Ed25519 signature of the SHA-256 hash of the 
> uncompressed heap. The hash is not stored as there is no point to do so - it 
> needs to be calculated anyway, and so this just signs the value that has been 
> calculated. If the calculated hash is correct, the signature is. If the 
> calculated hash is incorrect, the signature is incorrect. Just that easy.
> 
> And yes, this includes the whole certificate, so that the user can easily add 
> it to the system if he trusts the source from which he got the hpkg.
> 
> Now, how the certificate looks like:
> 
>       uint8   publicKey[32];
>       uint8   nameLength;
>       char*   name;
> 
> The name is *only* meant to be presented to the user, not as a security 
> feature. It will be important if the user does not trust a certificate 
> anymore, so he can remove it. If the user adds a hpkg that has an unknown 
> certificate, the user will get a dialog like this:
> 
> "You are trying to install {name of hpkg}, however, this software is signed 
> by a certificate your system does not know. The certificate claims to belong 
> to {certificate name}. Do you want to trust it and add it to the system? Only 
> do so if you obtained the software via a secure method and are indeed sure 
> that it actually belongs to {certificate name}!"
> [ Yes ] [ No ] [ Allow only this time ]
> 
> In order to prevent name spoofing (i.e. using a certificate that the user 
> accepted, but showing a different name or other tricks to confuse the user), 
> the certificate will be looked up in the certificate store like this:
> 
> Create an ID for the certificate that is sha256(concat(publicKey, name)). 
> Look if there's a certificate with that ID in the list of trusted 
> certificates (e.g. /system/package-certificates/ID). Generate the ID for the 
> file /system/package-certificates/ID and check if it's the same, just to be 
> sure. Then, compare the two certificates as an extra precaution (these two 
> prevent having the wrong ID/hash for a certificate).
> 
> So even if a user re-uses the public key for different names, it will not be 
> a problem and will not allow spoofing. The name can be added as an attribute 
> so that the user can later identify a certificate.
> 
> So the big advantage of this approach is that it is really easy and does not 
> have many attack vectors. It is much simpler than any PKI infrastructure, 
> does not have layers of protocols that allow attacks, does not have complex 
> certificate formats where we'd only use 1% of the fields etc.
> 
> Any thoughts on that? Is anything unclear? Did anybody spot a hole in it? I 
> already talked it over with a few people who are into security and it seemed 
> nobody could find a flaw so far.
> 
> --
> Jonathan

--
Jonathan

Other related posts: