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