opentitanlib/image/
manifest_ext.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::{Context, Result, ensure};
6use serde::{self, Deserialize, Serialize};
7use std::path::{Path, PathBuf};
8use thiserror::Error;
9use zerocopy::IntoBytes;
10
11use crate::chip::boolean::HardenedBool;
12use crate::crypto::mldsa::load_mldsa_key;
13use crate::image::manifest::*;
14use crate::image::manifest_def::le_bytes_to_word_arr;
15use crate::util::num_de::HexEncoded;
16use crate::with_unknown;
17use ml_dsa::{MlDsa87, VerifyingKey};
18use sphincsplus::{DecodeKey, SpxPublicKey};
19
20#[derive(Debug, Error)]
21pub enum ManifestExtError {
22    #[error("Extension ID 0x{0:x} has duplicate extension data.")]
23    DuplicateEntry(u32),
24}
25
26with_unknown! {
27    /// Known manifest extension variant IDs.
28    #[derive(Default)]
29    pub enum ManifestExtId: u32 {
30        spx_key = MANIFEST_EXT_ID_SPX_KEY,
31        spx_signature = MANIFEST_EXT_ID_SPX_SIGNATURE,
32        image_type = MANIFEST_EXT_ID_IMAGE_TYPE,
33        secver_write = MANIFEST_EXT_ID_SECVER_WRITE,
34        isfb = MANIFEST_EXT_ID_ISFB,
35        isfb_erase = MANIFEST_EXT_ID_ISFB_ERASE,
36        owner_transfer_blob = MANIFEST_EXT_ID_OWNER_TRANSFER_BLOB,
37        mldsa87_key = MANIFEST_EXT_ID_MLDSA87_KEY,
38        mldsa87_signature = MANIFEST_EXT_ID_MLDSA87_SIGNATURE,
39    }
40}
41
42/// Top level spec for manifest extension HJSON files.
43#[derive(Default, Debug, Deserialize, Serialize)]
44pub struct ManifestExtSpec {
45    pub extension_params: Vec<ManifestExtEntrySpec>,
46    #[serde(skip)]
47    relative_path: Option<PathBuf>,
48}
49
50#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
51pub struct ProductExpr {
52    pub mask: HexEncoded<u32>,
53    pub value: HexEncoded<u32>,
54}
55
56/// Specs for the known extension variants.
57///
58/// This includes a raw variant that can take any id, name, and value.
59#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
60pub enum ManifestExtEntrySpec {
61    #[serde(alias = "spx_key")]
62    SpxKey {
63        /// The path to the SPHINCS+ public or private key.
64        spx_key: PathBuf,
65    },
66    #[serde(alias = "spx_signature")]
67    SpxSignature {
68        /// The path to the SPHINCS+ signature.
69        spx_signature: PathBuf,
70    },
71    #[serde(alias = "mldsa87_key")]
72    Mldsa87Key {
73        /// The path to the ML-DSA-87 public or private key.
74        mldsa87_key: PathBuf,
75    },
76    #[serde(alias = "mldsa87_signature")]
77    Mldsa87Signature {
78        /// The path to the ML-DSA-87 signature.
79        mldsa87_signature: PathBuf,
80    },
81
82    #[serde(alias = "image_type")]
83    ImageType { image_type: u32 },
84
85    #[serde(alias = "secver_write")]
86    SecVerWrite {
87        /// Whether or not to write the security version into boot data.
88        secver_write: bool,
89    },
90
91    #[serde(alias = "integrator_specific_firmware_binding")]
92    Isfb {
93        strike_mask: HexEncoded<u128>,
94        product_expr: Vec<ProductExpr>,
95    },
96
97    #[serde(alias = "isfb_erase_policy")]
98    IsfbErasePolicy { erase_allowed: bool },
99
100    #[serde(alias = "owner_transfer_blob")]
101    OwnerTransferBlob {
102        owner_block: PathBuf,
103        #[serde(default)]
104        detached_signature: Option<PathBuf>,
105    },
106
107    #[serde(alias = "raw")]
108    Raw {
109        name: HexEncoded<u32>,
110        identifier: HexEncoded<u32>,
111        signed: bool,
112        #[serde(default)]
113        alignment: Option<HexEncoded<u32>>,
114        #[serde(default)]
115        value: Option<Vec<HexEncoded<u8>>>,
116        #[serde(default)]
117        file: Option<PathBuf>,
118    },
119}
120
121#[derive(Debug)]
122pub enum ManifestExtEntry {
123    SpxKey(ManifestExtSpxKey),
124    SpxSignature(Box<ManifestExtSpxSignature>),
125    Mldsa87Key(Box<ManifestExtMldsa87Key>),
126    Mldsa87Signature(Box<ManifestExtMldsa87Signature>),
127    ImageType(ManifestExtImageType),
128    SecVerWrite(ManifestExtSecVerWrite),
129    Isfb(ManifestExtIsfb),
130    IsfbErasePolicy(ManifestExtIsfbErasePolicy),
131    OwnerTransferBlob {
132        header: ManifestExtHeader,
133        owner_block: Vec<u8>,
134        detached_signature: Option<Vec<u8>>,
135    },
136    Raw {
137        header: ManifestExtHeader,
138        alignment: u32,
139        data: Vec<u8>,
140    },
141}
142
143impl ManifestExtSpec {
144    /// Reads in a `ManifestExtSpec` from an HJSON file.
145    ///
146    /// The parent of `path` (the directory containing the HJSON file to be loaded) is used when
147    /// resolving relative paths for any extension data that references a file.
148    pub fn read_from_file(path: &Path) -> Result<Self> {
149        let mut spec: Self = deser_hjson::from_str(&std::fs::read_to_string(path)?)?;
150        spec.relative_path = path.parent().map(|v| v.to_owned());
151        Ok(spec)
152    }
153
154    /// The partent of the path that was provided when loading this spec.
155    pub fn source_path(&self) -> Option<&Path> {
156        self.relative_path.as_deref()
157    }
158}
159
160impl ManifestExtEntrySpec {
161    pub fn id(&self) -> u32 {
162        match self {
163            ManifestExtEntrySpec::SpxKey { spx_key: _ } => MANIFEST_EXT_ID_SPX_KEY,
164            ManifestExtEntrySpec::SpxSignature { spx_signature: _ } => {
165                MANIFEST_EXT_ID_SPX_SIGNATURE
166            }
167            ManifestExtEntrySpec::Mldsa87Key { .. } => MANIFEST_EXT_ID_MLDSA87_KEY,
168            ManifestExtEntrySpec::Mldsa87Signature { .. } => MANIFEST_EXT_ID_MLDSA87_SIGNATURE,
169            ManifestExtEntrySpec::SecVerWrite { .. } => MANIFEST_EXT_ID_SECVER_WRITE,
170            ManifestExtEntrySpec::Isfb { .. } => MANIFEST_EXT_ID_ISFB,
171            ManifestExtEntrySpec::IsfbErasePolicy { .. } => MANIFEST_EXT_ID_ISFB_ERASE,
172            ManifestExtEntrySpec::ImageType { image_type: _ } => MANIFEST_EXT_ID_IMAGE_TYPE,
173            ManifestExtEntrySpec::OwnerTransferBlob { .. } => MANIFEST_EXT_ID_OWNER_TRANSFER_BLOB,
174            ManifestExtEntrySpec::Raw { identifier, .. } => **identifier,
175        }
176    }
177
178    pub fn is_signed(&self) -> bool {
179        match self {
180            ManifestExtEntrySpec::SpxKey { .. }
181            | ManifestExtEntrySpec::Mldsa87Key { .. }
182            | ManifestExtEntrySpec::SecVerWrite { .. }
183            | ManifestExtEntrySpec::Isfb { .. }
184            | ManifestExtEntrySpec::IsfbErasePolicy { .. }
185            | ManifestExtEntrySpec::ImageType { .. } => true,
186            ManifestExtEntrySpec::SpxSignature { .. }
187            | ManifestExtEntrySpec::Mldsa87Signature { .. }
188            | ManifestExtEntrySpec::OwnerTransferBlob { .. } => false,
189            ManifestExtEntrySpec::Raw { signed, .. } => *signed,
190        }
191    }
192}
193
194impl ManifestExtEntry {
195    /// Creates a new manifest extension from a given SPHINCS+ `key`.
196    pub fn new_spx_key_entry(key: &SpxPublicKey) -> Result<Self> {
197        Ok(ManifestExtEntry::SpxKey(ManifestExtSpxKey {
198            header: ManifestExtHeader {
199                identifier: MANIFEST_EXT_ID_SPX_KEY,
200                name: MANIFEST_EXT_NAME_SPX_KEY,
201            },
202            key: SigverifySpxKey {
203                data: le_bytes_to_word_arr(key.as_bytes())?,
204            },
205        }))
206    }
207
208    /// Creates a new manifest extension from a given SPHINCS+ `signature`.
209    pub fn new_spx_signature_entry(signature: &[u8]) -> Result<Self> {
210        Ok(ManifestExtEntry::SpxSignature(Box::new(
211            ManifestExtSpxSignature {
212                header: ManifestExtHeader {
213                    identifier: MANIFEST_EXT_ID_SPX_SIGNATURE,
214                    name: MANIFEST_EXT_NAME_SPX_SIGNATURE,
215                },
216                signature: SigverifySpxSignature {
217                    data: le_bytes_to_word_arr(signature)?,
218                },
219            },
220        )))
221    }
222
223    /// Creates a new manifest extension from a given ML-DSA-87 `key`.
224    pub fn new_mldsa87_key_entry(key: &VerifyingKey<MlDsa87>) -> Result<Self> {
225        Ok(ManifestExtEntry::Mldsa87Key(Box::new(
226            ManifestExtMldsa87Key {
227                header: ManifestExtHeader {
228                    identifier: MANIFEST_EXT_ID_MLDSA87_KEY,
229                    name: MANIFEST_EXT_NAME_MLDSA87_KEY,
230                },
231                key: SigverifyMldsa87Key {
232                    data: le_bytes_to_word_arr(&key.encode())?,
233                },
234            },
235        )))
236    }
237
238    /// Creates a new manifest extension from a given ML-DSA-87 `signature`.
239    pub fn new_mldsa87_signature_entry(signature: &[u8]) -> Result<Self> {
240        ensure!(
241            signature.len() == MLDSA87_SIGNATURE_BYTES,
242            "Unexpected ML-DSA-87 signature length {}",
243            signature.len()
244        );
245        Ok(ManifestExtEntry::Mldsa87Signature(Box::new(
246            ManifestExtMldsa87Signature {
247                header: ManifestExtHeader {
248                    identifier: MANIFEST_EXT_ID_MLDSA87_SIGNATURE,
249                    name: MANIFEST_EXT_NAME_MLDSA87_SIGNATURE,
250                },
251                signature: SigverifyMldsa87Signature {
252                    data: le_bytes_to_word_arr(signature)?,
253                },
254            },
255        )))
256    }
257
258    pub fn new_image_type_entry(image_type: u32) -> Result<Self> {
259        Ok(ManifestExtEntry::ImageType(ManifestExtImageType {
260            header: ManifestExtHeader {
261                identifier: MANIFEST_EXT_ID_IMAGE_TYPE,
262                name: MANIFEST_EXT_NAME_IMAGE_TYPE,
263            },
264            image_type,
265        }))
266    }
267
268    pub fn new_secver_write_entry(write: u32) -> Result<Self> {
269        Ok(ManifestExtEntry::SecVerWrite(ManifestExtSecVerWrite {
270            header: ManifestExtHeader {
271                identifier: MANIFEST_EXT_ID_SECVER_WRITE,
272                name: MANIFEST_EXT_NAME_SECVER_WRITE,
273            },
274            write,
275        }))
276    }
277
278    pub fn new_isfb_erase_policy_entry(erase_allowed: u32) -> Result<Self> {
279        Ok(ManifestExtEntry::IsfbErasePolicy(
280            ManifestExtIsfbErasePolicy {
281                header: ManifestExtHeader {
282                    identifier: MANIFEST_EXT_ID_ISFB_ERASE,
283                    name: MANIFEST_EXT_NAME_ISFB_ERASE,
284                },
285                erase_allowed,
286            },
287        ))
288    }
289
290    pub fn new_isfb_entry(strike_mask: u128, product_expr_spec: Vec<ProductExpr>) -> Result<Self> {
291        let product_expr_count = product_expr_spec.len() as u32;
292        let product_expr = product_expr_spec
293            .into_iter()
294            .map(|expr| ManifestExtIsfbProductExpr {
295                mask: expr.mask.0,
296                value: expr.value.0,
297            })
298            .collect();
299        Ok(ManifestExtEntry::Isfb(ManifestExtIsfb {
300            header: ManifestExtHeader {
301                identifier: MANIFEST_EXT_ID_ISFB,
302                name: MANIFEST_EXT_NAME_ISFB,
303            },
304            strike_mask,
305            product_expr_count,
306            product_expr,
307        }))
308    }
309
310    /// Creates a new manifest extension from a given `spec`.
311    pub fn from_spec(spec: &ManifestExtEntrySpec) -> Result<Self> {
312        Ok(match spec {
313            ManifestExtEntrySpec::SpxKey { spx_key } => {
314                ManifestExtEntry::new_spx_key_entry(&SpxPublicKey::read_pem_file(spx_key)?)?
315            }
316            ManifestExtEntrySpec::SpxSignature { spx_signature } => {
317                ManifestExtEntry::new_spx_signature_entry(&std::fs::read(spx_signature)?)?
318            }
319            ManifestExtEntrySpec::Mldsa87Key { mldsa87_key } => {
320                ManifestExtEntry::new_mldsa87_key_entry(&load_mldsa_key::<MlDsa87>(mldsa87_key)?.0)?
321            }
322            ManifestExtEntrySpec::Mldsa87Signature { mldsa87_signature } => {
323                ManifestExtEntry::new_mldsa87_signature_entry(&std::fs::read(mldsa87_signature)?)?
324            }
325            ManifestExtEntrySpec::ImageType { image_type } => {
326                ManifestExtEntry::new_image_type_entry(*image_type)?
327            }
328            ManifestExtEntrySpec::SecVerWrite { secver_write } => {
329                ManifestExtEntry::new_secver_write_entry(
330                    (if *secver_write {
331                        HardenedBool::True
332                    } else {
333                        HardenedBool::False
334                    })
335                    .into(),
336                )?
337            }
338            ManifestExtEntrySpec::IsfbErasePolicy { erase_allowed } => {
339                ManifestExtEntry::new_isfb_erase_policy_entry(
340                    (if *erase_allowed {
341                        HardenedBool::True
342                    } else {
343                        HardenedBool::False
344                    })
345                    .into(),
346                )?
347            }
348            ManifestExtEntrySpec::Isfb {
349                strike_mask,
350                product_expr,
351            } => ManifestExtEntry::new_isfb_entry(**strike_mask, product_expr.to_vec())?,
352            ManifestExtEntrySpec::OwnerTransferBlob {
353                owner_block,
354                detached_signature,
355            } => {
356                let owner_data = std::fs::read(owner_block).with_context(|| {
357                    format!("Failed to read owner block file {:?}", owner_block)
358                })?;
359                anyhow::ensure!(
360                    owner_data.len() == 2048,
361                    "Owner block must be exactly 2048 bytes (got {})",
362                    owner_data.len()
363                );
364                let sig_data = match detached_signature {
365                    Some(path) => {
366                        let mut data = std::fs::read(path).with_context(|| {
367                            format!("Failed to read detached signature file {:?}", path)
368                        })?;
369                        anyhow::ensure!(
370                            data.len() <= 8192,
371                            "Detached signature size ({}) exceeds maximum limit (8192 bytes)",
372                            data.len()
373                        );
374                        data.resize(8192, 0xff);
375                        Some(data)
376                    }
377                    None => None,
378                };
379                ManifestExtEntry::OwnerTransferBlob {
380                    header: ManifestExtHeader {
381                        identifier: MANIFEST_EXT_ID_OWNER_TRANSFER_BLOB,
382                        name: MANIFEST_EXT_NAME_OWNER_TRANSFER_BLOB,
383                    },
384                    owner_block: owner_data,
385                    detached_signature: sig_data,
386                }
387            }
388            ManifestExtEntrySpec::Raw {
389                name,
390                identifier,
391                alignment,
392                value,
393                file,
394                ..
395            } => {
396                let data = if let Some(path) = file {
397                    std::fs::read(path)
398                        .with_context(|| format!("Failed to read raw extension file {:?}", path))?
399                } else if let Some(val) = value {
400                    val.iter().map(|v| **v).collect()
401                } else {
402                    anyhow::bail!("Raw extension must specify either value or file");
403                };
404                ManifestExtEntry::Raw {
405                    header: ManifestExtHeader {
406                        identifier: **identifier,
407                        name: **name,
408                    },
409                    alignment: alignment.as_ref().map(|v| **v).unwrap_or(4),
410                    data,
411                }
412            }
413        })
414    }
415
416    /// Returns the required alignment of this extension in bytes.
417    pub fn alignment(&self) -> u32 {
418        match self {
419            ManifestExtEntry::OwnerTransferBlob { .. } => 2048,
420            ManifestExtEntry::Raw { alignment, .. } => *alignment,
421            _ => 4,
422        }
423    }
424
425    /// Returns the header portion of this extension.
426    pub fn header(&self) -> &ManifestExtHeader {
427        match self {
428            ManifestExtEntry::SpxKey(key) => &key.header,
429            ManifestExtEntry::SpxSignature(sig) => &sig.header,
430            ManifestExtEntry::Mldsa87Key(key) => &key.header,
431            ManifestExtEntry::Mldsa87Signature(sig) => &sig.header,
432            ManifestExtEntry::ImageType(image_type) => &image_type.header,
433            ManifestExtEntry::SecVerWrite(sv) => &sv.header,
434            ManifestExtEntry::Isfb(isfb) => &isfb.header,
435            ManifestExtEntry::IsfbErasePolicy(erase) => &erase.header,
436            ManifestExtEntry::OwnerTransferBlob { header, .. } => header,
437            ManifestExtEntry::Raw {
438                header,
439                alignment: _,
440                data: _,
441            } => header,
442        }
443    }
444
445    /// Allocates a new byte `Vec<u8>` and writes the binary extension data to it.
446    pub fn to_vec(&self) -> Vec<u8> {
447        match self {
448            ManifestExtEntry::SpxKey(key) => key.as_bytes().to_vec(),
449            ManifestExtEntry::SpxSignature(sig) => sig.as_bytes().to_vec(),
450            ManifestExtEntry::Mldsa87Key(key) => key.as_bytes().to_vec(),
451            ManifestExtEntry::Mldsa87Signature(sig) => sig.as_bytes().to_vec(),
452            ManifestExtEntry::ImageType(image_type) => image_type.as_bytes().to_vec(),
453            ManifestExtEntry::SecVerWrite(sv) => sv.as_bytes().to_vec(),
454            ManifestExtEntry::Isfb(isfb) => isfb.to_vec().unwrap(),
455            ManifestExtEntry::IsfbErasePolicy(erase) => erase.as_bytes().to_vec(),
456            ManifestExtEntry::OwnerTransferBlob {
457                header,
458                owner_block,
459                detached_signature,
460            } => {
461                let mut v = header.as_bytes().to_vec();
462                v.extend_from_slice(owner_block);
463                if let Some(sig) = detached_signature {
464                    v.extend_from_slice(sig);
465                }
466                v
467            }
468            ManifestExtEntry::Raw {
469                header,
470                alignment: _,
471                data,
472            } => header.as_bytes().iter().chain(data).copied().collect(),
473        }
474    }
475}
476
477#[cfg(test)]
478mod tests {
479    use super::*;
480    use crate::util::hexdump::hexdump_string;
481    use crate::util::num_de::HexEncoded;
482    use crate::util::testdata;
483
484    #[test]
485    fn test_manifest_ext_from_hjson() {
486        let spec = ManifestExtSpec::read_from_file(&testdata("image/manifest_ext.hjson")).unwrap();
487        assert_eq!(spec.source_path(), Some(testdata("image").as_path()));
488        assert_eq!(spec.extension_params.len(), 9);
489        assert_eq!(
490            spec.extension_params[0],
491            ManifestExtEntrySpec::SpxKey {
492                spx_key: "test_spx.pem".into()
493            }
494        );
495        assert!(spec.extension_params[0].is_signed());
496        assert_eq!(
497            spec.extension_params[1],
498            ManifestExtEntrySpec::SecVerWrite { secver_write: true }
499        );
500        assert!(spec.extension_params[1].is_signed());
501        assert_eq!(
502            spec.extension_params[2],
503            ManifestExtEntrySpec::Isfb {
504                strike_mask: HexEncoded(0x0fedcba987654321fedcba9876543210),
505                product_expr: vec![
506                    ProductExpr {
507                        mask: HexEncoded(0xffffffff),
508                        value: HexEncoded(0xa5a5a5a5),
509                    },
510                    ProductExpr {
511                        mask: HexEncoded(0xf0f0f0f0),
512                        value: HexEncoded(0xa0a0a0a0),
513                    },
514                ]
515            }
516        );
517        assert!(spec.extension_params[2].is_signed());
518        assert_eq!(
519            spec.extension_params[3],
520            ManifestExtEntrySpec::IsfbErasePolicy {
521                erase_allowed: false
522            }
523        );
524        assert!(spec.extension_params[3].is_signed());
525        assert_eq!(
526            spec.extension_params[4],
527            ManifestExtEntrySpec::Raw {
528                name: HexEncoded(0xbeef),
529                identifier: HexEncoded(0xabcd),
530                signed: true,
531                alignment: None,
532                value: Some([0x01, 0x23, 0x45, 0x67].map(HexEncoded).to_vec()),
533                file: None,
534            }
535        );
536        assert!(spec.extension_params[4].is_signed());
537        assert_eq!(
538            spec.extension_params[5],
539            ManifestExtEntrySpec::SpxSignature {
540                spx_signature: "test_signature.bin".into()
541            }
542        );
543        assert!(!spec.extension_params[5].is_signed());
544        assert_eq!(
545            spec.extension_params[6],
546            ManifestExtEntrySpec::OwnerTransferBlob {
547                owner_block: "owner_block.bin".into(),
548                detached_signature: Some("signature.bin".into()),
549            }
550        );
551        assert!(!spec.extension_params[6].is_signed());
552        assert_eq!(
553            spec.extension_params[7],
554            ManifestExtEntrySpec::Mldsa87Key {
555                mldsa87_key: "test_mldsa87.pem".into()
556            }
557        );
558        assert!(spec.extension_params[7].is_signed());
559        assert_eq!(
560            spec.extension_params[8],
561            ManifestExtEntrySpec::Mldsa87Signature {
562                mldsa87_signature: "test_mldsa87_signature.bin".into()
563            }
564        );
565        assert!(!spec.extension_params[8].is_signed());
566    }
567
568    const MAN_EXT_ISFB_CONF: &str = "\
56900000000: 49 53 46 42 49 53 46 42 10 32 54 76 98 ba dc fe  ISFBISFB.2Tv....
57000000010: 21 43 65 87 a9 cb ed 0f 02 00 00 00 4f 30 50 10  !Ce.........O0P.
57100000020: 05 00 00 01 f0 f0 f0 f0 a0 a0 a0 a0              ............
572";
573    #[test]
574    fn test_man_ext_isfb_write() -> Result<()> {
575        let isfb = ManifestExtEntry::new_isfb_entry(
576            0x0fedcba987654321fedcba9876543210,
577            vec![
578                ProductExpr {
579                    mask: HexEncoded(0x1050304f),
580                    value: HexEncoded(0x01000005),
581                },
582                ProductExpr {
583                    mask: HexEncoded(0xf0f0f0f0),
584                    value: HexEncoded(0xa0a0a0a0),
585                },
586            ],
587        )?;
588
589        let bin = isfb.to_vec();
590        eprintln!("{}", hexdump_string(&bin)?);
591        assert_eq!(hexdump_string(&bin)?, MAN_EXT_ISFB_CONF);
592        Ok(())
593    }
594
595    const MAN_EXT_ISFB_ERASE_POLICY: &str = "\
59600000000: 49 53 46 45 49 53 46 45 d4 01 00 00              ISFEISFE....
597";
598
599    #[test]
600    fn test_man_ext_isfb_erase_policy_write() -> Result<()> {
601        let isfb = ManifestExtEntry::new_isfb_erase_policy_entry(HardenedBool::False.into())?;
602
603        let bin = isfb.to_vec();
604        eprintln!("{}", hexdump_string(&bin)?);
605        assert_eq!(hexdump_string(&bin)?, MAN_EXT_ISFB_ERASE_POLICY);
606        Ok(())
607    }
608}