[][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]

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.

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.

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.

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.

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.

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.

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> Gbl<E, MaybeSigned<'a>> where
    E: EncryptionState<'a>, 
[src]

MaybeSigned -> (Not)Signed downcasting methods.

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.

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.

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]

Attempts to verify the ECDSA signature attached to the GBL.

If the signature was not created by the private key belonging to pem_pubkey, the signature was probably forged and an error will be returned. An error will also be returned if the public key is malformed or otherwise invalid.

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

  • pem_pubkey: The public key in PEM ASCII format (-----BEGIN PUBLIC KEY----- etc.).

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]

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

  • pem_private_key: The unencrypted private key in PEM ASCII format (-----BEGIN EC PRIVATE KEY----- etc.).

impl<'a> Gbl<Encrypted<'a>, NotSigned<'a>>
[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.

Takes ownership of any borrowed data in self.

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

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.

Converts the GBL file to its binary representation.

Serializes the binary representation of this GBL into a writer.

Returns whether self contains a digital signature.

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

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<E: Debug, S: Debug> Debug for Gbl<E, S>
[src]

Auto Trait Implementations

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

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

Blanket Implementations

impl<T> From for T
[src]

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

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

🔬 This is a nightly-only experimental API. (try_from)

The type returned in the event of a conversion error.

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

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

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

🔬 This is a nightly-only experimental API. (try_from)

The type returned in the event of a conversion error.

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