[][src]Struct gbl::Gbl

pub struct Gbl<E, S> { /* fields omitted */ }

In-memory representation of a GBL file.

Typestate

This struct makes heavy use of typestate to track whether the GBL is encrypted or contains an ECDSA signature: The E type parameter can be any of Encrypted, NotEncrypted or MaybeEncrypted to indicate whether the program data in the GBL is encrypted, while S can be any of Signed, NotSigned or MaybeSigned to indicate the presence of a signature.

Typestate is used to make misuse of the APIs in this crate as difficult as possible. It rules out many possibly unwanted operations statically, such as:

  • Encrypting an already-encrypted GBL.
  • Decrypting a GBL that is not encrypted.
  • Signing a GBL that already has a signature.
  • Adding a ProgramData section to an encrypted GBL (only encrypted section are allowed there) or to a signed GBL (which would invalidate the signature).
  • Accessing the plain-text data sections using data_sections() on an encrypted GBL.

Attempting to perform any of those operations will make the program fail compilation. The only operations that perform runtime checking are the into_encrypted/signed methods mentioned above.

The downside of such a typestate-based API is that it is rather cumbersome and complex. However, correctness was deemed more important here (in fact, we've already had internal API-misuse accidents that would've been prevented by the typestate-based API).

Maybe

The Maybe* typestates indicate that there is no compile-time knowledge of the state. They are present when parsing an external GBL file and provide their information only at runtime.

On Gbl objects containing Maybe*, only a few general methods are available. To get access to the methods that require more precise typestate, into_encrypted, into_not_encrypted, into_signed, or into_not_signed can be called to effectively downcast from MaybeX to X or NotX.

Examples

A simple example that shows how to deal with Maybe* typestate:

use gbl::Gbl;
use gbl::marker::*;

// This GBL is neither signed nor encrypted
let raw_bytes: &[u8] = include_bytes!("../test-data/empty/empty.gbl");

let gbl: Gbl<MaybeEncrypted, MaybeSigned> = Gbl::parse(raw_bytes)?;
match gbl.into_not_encrypted() {
	// `into_not_encrypted` returns a `Gbl<NotEncrypted, _>` in the success case
	Ok(not_encrypted) => {
		// Let's write out the type we get in the `Ok` branch:
		let not_encrypted: Gbl<NotEncrypted, MaybeSigned> = not_encrypted;

		// Getting a `NotEncrypted` GBL just made the `data_sections()` accessor available:
		not_encrypted.data_sections();

		// In almost all cases, you want to get rid of the `MaybeSigned` as well.
		// Let's just unwrap that one to keep it simple:
		let gbl: Gbl<NotEncrypted, NotSigned> = not_encrypted.into_not_signed().unwrap();
		// (you can remove the `MaybeEncrypted` and `MaybeSigned` in any order)

		// Now that we have a `Gbl<NotEncrypted, NotSigned>`, a lot of useful methods
		// just became available: `push_data_section`, `encrypt`, `sign`, ...
		// Refer to the API documentation for more details on methods and their availability.
	}
	Err(encrypted) => {
		// The GBL *is* encrypted. We won't handle that case here and leave it as an
		// exercise to the reader.
		unimplemented!("GBL is encrypted");
	}
}

Methods

impl<'a> Gbl<MaybeEncrypted<'a>, MaybeSigned<'a>>[src]

pub fn parse<T: AsRef<[u8]> + ?Sized>(bytes: &'a T) -> Result<Self, Error>[src]

Parses a GBL file from raw bytes.

The resulting Gbl will be MaybeEncrypted and MaybeSigned, because those states can't be statically determined when parsing an existing GBL. You can use into_encrypted, into_signed, etc. to downcast to a more specific typestate that has more methods available.

Parsing is protected against malicious GBL files that specify very large sizes or contain an abnormal number of tags to cause a DoS via memory exhaustion. Note that this protection does not extend to the user code that reads the GBL file into memory.

impl<'a> Gbl<NotEncrypted<'a>, NotSigned<'a>>[src]

Methods that only work on non-encrypted and non-signed GBLs.

pub fn from_app_image(image: AppImage<'a>) -> Self[src]

Creates a Gbl object from a raw application image.

The resulting GBL file will contain the AppInfo from the given image as well as a single ProgramData section writing the raw image data to the device flash.

pub fn from_parts(app_info: AppInfo, data: ProgramData<'a>) -> Self[src]

Creates a new GBL file from an existing AppInfo structure and a ProgramData section.

Additional program data sections can be added by calling push_data_section.

pub fn push_data_section(&mut self, section: ProgramData<'a>)[src]

Appends a ProgramData section to the data section list.

It is the user's responsibility to ensure that no sections overlap (or reference invalid addresses).

Also see data_sections for read-only access to all ProgramData sections.

pub fn encrypt(self, key: AesKey) -> Gbl<Encrypted<'a>, NotSigned<'a>>[src]

Encrypts the content of this GBL file using an AES-128 key.

This will generate a random 12-Byte nonce using the operating system's random number generator. The nonce will be used for encryption and decryption and is stored inside the encryption header inside the encrypted GBL.

Note that the validity of the key cannot be checked: Passing an invalid key will result in encryption succeeding, but resulting in garbage data, which will then fail to parse properly.

Method availability

This method is only available when self is NotEncrypted and NotSigned. It turns a NotEncrypted and NotSigned GBL into an Encrypted and NotSigned GBL.

impl<'a, S> Gbl<MaybeEncrypted<'a>, S> where
    S: SignatureState<'a>, 
[src]

MaybeEncrypted -> (Not)Encrypted downcasting methods.

pub fn into_encrypted(
    self
) -> Result<Gbl<Encrypted<'a>, S>, Gbl<NotEncrypted<'a>, S>>
[src]

Inspects the MaybeEncrypted, downcasting self to a Gbl<Encrypted, _> if it is encrypted.

Otherwise, downcasts self to a Gbl<NotEncrypted, _>. This means that the Maybe* gets stripped in either case.

Note that this will never actually modify or drop data in self. All that changes is the type, potentially making more methods available on the returned Gbl.

This will not modify the signature typestate S. It works with any S and simply passes it through.

pub fn into_not_encrypted(
    self
) -> Result<Gbl<NotEncrypted<'a>, S>, Gbl<Encrypted<'a>, S>>
[src]

Inspects the MaybeEncrypted, downcasting self to a Gbl<NotEncrypted, _> if it is not encrypted.

Otherwise, downcasts self to a Gbl<Encrypted, _>. This means that the Maybe* gets stripped in either case.

Note that this will never actually modify or drop data in self. All that changes is the type, potentially making more methods available on the returned Gbl.

This will not modify the signature typestate S. It works with any S and simply passes it through.

impl<'a, E, S> Gbl<E, S> where
    E: EncryptionState<'a>,
    S: SignatureState<'a>, 
[src]

Generic upcasting methods to Maybe* variants.

pub fn into_maybe_encrypted(self) -> Gbl<MaybeEncrypted<'a>, S>[src]

Erases the encryption type state by upcasting to MaybeEncrypted.

This can be used to avoid code duplication in code that needs to handle both encrypted and non-encrypted GBLs.

This conversion can also be performed using Into/From.

pub fn into_maybe_signed(self) -> Gbl<E, MaybeSigned<'a>>[src]

Erases the signature type state by upcasting to MaybeSigned.

This can be used to avoid code duplication in code that needs to handle both signed and non-signed GBLs.

This conversion can also be performed using Into/From.

impl<'a, E> Gbl<E, MaybeSigned<'a>> where
    E: EncryptionState<'a>, 
[src]

MaybeSigned -> (Not)Signed downcasting methods.

pub fn into_signed(self) -> Result<Gbl<E, Signed<'a>>, Gbl<E, NotSigned<'a>>>[src]

Inspects the MaybeSigned, downcasting self to a Gbl<_, Signed> if it is signed.

Otherwise, downcasts self to a Gbl<_, NotSigned>. This means that the Maybe* gets stripped in either case.

Note that this will never actually modify or drop data in self. All that changes is the type, potentially making more methods available on the returned Gbl.

This will not modify the encryption typestate E. It works with any E and simply passes it through.

pub fn into_not_signed(
    self
) -> Result<Gbl<E, NotSigned<'a>>, Gbl<E, Signed<'a>>>
[src]

Inspects the MaybeSigned, downcasting self to a Gbl<_, NotSigned> if it is signed.

Otherwise, downcasts self to a Gbl<_, Signed>. This means that the Maybe* gets stripped in either case.

Note that this will never actually modify or drop data in self. All that changes is the type, potentially making more methods available on the returned Gbl.

This will not modify the encryption typestate E. It works with any E and simply passes it through.

impl<'a, S> Gbl<NotEncrypted<'a>, S> where
    S: SignatureState<'a>, 
[src]

Methods available only on non-encrypted GBLs. Signature may or may not be present.

pub fn data_sections(&self) -> &[ProgramData<'a>][src]

Returns the data sections to be programmed to the device's flash memory.

This method is only available if self is NotEncrypted, because an encrypted GBL does not allow reading the data sections.

Also see push_data_section.

impl<'a, E> Gbl<E, Signed<'a>> where
    E: EncryptionState<'a>, 
[src]

pub fn verify_signature(&self, pubkey: &P256PublicKey) -> Result<(), Error>[src]

Attempts to verify the ECDSA signature attached to the GBL.

If the signature was not created by the private key belonging to pubkey, an error will be returned.

If the GBL is encrypted, the signature is computed over the encrypted data. Consequently, decrypting the GBL disposes of the signature. Check the signature before decrypting!

Parameters

  • pubkey: The public P-256 key to verify against.

pub fn remove_signature(self) -> Gbl<E, NotSigned<'a>>[src]

Strips the signature from self without verifying it.

This converts a Signed GBL into a NotSigned one, enabling methods that require the GBL to have no signature (such as push_data_section and encrypt).

impl<'a, E> Gbl<E, NotSigned<'a>> where
    E: EncryptionState<'a>, 
[src]

pub fn sign(self, key: &P256KeyPair) -> Result<Gbl<E, Signed<'a>>, Error>[src]

Creates and appends a digital signature for self using a private EC key.

Returns the signed GBL.

Note that the signature created by this method is attached to the GBL container, not the contained application image. In other words, this signature can not be checked by the bootloader during secure boot. If you want to use secure boot, you need to sign the application image itself by using AppImage::sign. Also be aware that flashing an application image with an invalid signature will prevent the device from rebooting back into it, so you likely want to have both a signed application image and a signed GBL container you can check before flashing.

Parameters

  • key: The P-256 keypair to sign with.

impl<'a> Gbl<Encrypted<'a>, NotSigned<'a>>[src]

pub fn decrypt(
    self,
    key: AesKey
) -> Result<Gbl<NotEncrypted<'a>, NotSigned<'a>>, Error>
[src]

Decrypts the content of this GBL file using a raw AES-128 key.

The decrypted data will be parsed into GBL tags and returned as a new Gbl object based on self.

Note that the validity of the key cannot be checked: Passing an invalid key will result in decryption succeeding, but results in garbage data, which will then fail to parse properly.

impl<'a, E, S> Gbl<E, S> where
    E: EncryptionState<'a>,
    S: SignatureState<'a>, 
[src]

General methods that work on GBLs regardless of encryption/signing state.

pub fn into_owned(self) -> Gbl<E::StaticSelf, S::StaticSelf>[src]

Takes ownership of any borrowed data in self.

This will heap-allocate owned storage for all data in self and copy the data there.

pub fn clone(&'a self) -> Self[src]

A cheap-ish, lifetime-restricted version of Clone.

The returned object will share as much data as possible with self, but cannot outlive it. You can call .into_owned() on the returned object to make it own all of its data.

pub fn to_bytes(&self) -> Vec<u8>[src]

Converts the GBL file to its binary representation.

pub fn write<W: Write>(&self, writer: W) -> Result<()>[src]

Serializes the binary representation of this GBL into a writer.

pub fn is_signed(&self) -> bool[src]

Returns whether self contains a digital signature.

Call verify_signature to check if the signature belongs to a known key pair.

pub fn is_encrypted(&self) -> bool[src]

Returns whether self contains encrypted program data.

If this is the case, you must call decrypt to get access to the contained data.

Trait Implementations

impl<'a, S: SignatureState<'a>> From<Gbl<Encrypted<'a>, S>> for Gbl<MaybeEncrypted<'a>, S>[src]

impl<'a, S: SignatureState<'a>> From<Gbl<NotEncrypted<'a>, S>> for Gbl<MaybeEncrypted<'a>, S>[src]

impl<'a, E: EncryptionState<'a>> From<Gbl<E, Signed<'a>>> for Gbl<E, MaybeSigned<'a>>[src]

impl<'a, E: EncryptionState<'a>> From<Gbl<E, NotSigned<'a>>> for Gbl<E, MaybeSigned<'a>>[src]

impl<E: Debug, S: Debug> Debug for Gbl<E, S>[src]

Auto Trait Implementations

impl<E, S> Sync for Gbl<E, S> where
    E: Sync,
    S: Sync

impl<E, S> Send for Gbl<E, S> where
    E: Send,
    S: Send

impl<E, S> Unpin for Gbl<E, S> where
    E: Unpin,
    S: Unpin

impl<E, S> RefUnwindSafe for Gbl<E, S> where
    E: RefUnwindSafe,
    S: RefUnwindSafe

impl<E, S> UnwindSafe for Gbl<E, S> where
    E: UnwindSafe,
    S: UnwindSafe

Blanket Implementations

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> Any for T where
    T: 'static + ?Sized
[src]