// Verifies the hashes and signature of a zip file at the given path.
Verifies the hashes and signature of a zip file at the given path.
Verifies the hashes and signature of a zip file at the given path .
pub fn verify_zip<P: AsRef<Path>>(path: P, cert_type: &str) -> Result<(), ZipVerificationError> {
    let file = File::open(path).map_err(|_| ZipVerificationError::NoSuchFile)?;
    let mut archive = ZipArchive::new(file).map_err(|_| ZipVerificationError::InvalidZip)?;
    // 1. Verify the presence of mandatory files in META-INF. Any other file will be
    // referenced in the hash list in META-INF/manifest.mf
    for name in [
        "META-INF/zigbert.rsa",
        "META-INF/zigbert.sf",
        "META-INF/manifest.mf",
    ]
    .iter()
    {
        let _ = archive
            .by_name(name)
            .map_err(|_| ZipVerificationError::MissingMetaFile((*name).into()))?;
    }
    // 2. Get the parsed manifest.
    let mut content = Vec::new();
    {
        let mut file = archive.by_name("META-INF/manifest.mf").unwrap();
        let _ = file
            .read_to_end(&mut content)
            .map_err(|_| ZipVerificationError::InvalidZip)?;
    }
    let mut cursor = Cursor::new(content);
    if let Ok(manifest) = read_manifest(&mut cursor) {
        if manifest.version != "1.0" {
            return Err(ZipVerificationError::InvalidManifest);
        }
        // 3. Check that the list of files in the manifest matches the list of files in the zip:
        // - the total number of files in the zip must be manifest.entries + 3 (special the META-INF ones)
        // - every file listed in the manifest must exist.
        // - their hashes must match.
        if manifest.entries.len() + 3 != archive.len() {
            return Err(ZipVerificationError::InvalidFileList);
        }
        for entry in manifest.entries {
            match archive.by_name(&entry.name) {
                Err(_) => return Err(ZipVerificationError::InvalidFileList),
                Ok(mut zipentry) => {
                    if let Some(sha1) = entry.sha1 {
                        check_entry_digest(
                            &mut zipentry,
                            &digest::SHA1_FOR_LEGACY_USE_ONLY,
                            &sha1,
                        )?;
                    } else if let Some(sha256) = entry.sha256 {
                        check_entry_digest(&mut zipentry, &digest::SHA256, &sha256)?;
                    }
                }
            }
        }
        let mut sf_content = Vec::new();
        {
            let mut file = archive.by_name("META-INF/zigbert.sf").unwrap();
            let _ = file
                .read_to_end(&mut sf_content)
                .map_err(|_| ZipVerificationError::InvalidZip)?;
        }
        let mut sf_cursor = Cursor::new(sf_content);
        // 4. Use the META-INF/zigbert.sf to check the hash of META-INF/manifest.mf
        match read_signature_manifest(&mut sf_cursor) {
            Ok(manifest_hash) => {
                check_entry_digest(
                    &mut archive.by_name("META-INF/manifest.mf").unwrap(),
                    &digest::SHA1_FOR_LEGACY_USE_ONLY,
                    &manifest_hash,
                )?;
            }
            Err(_) => return Err(ZipVerificationError::InvalidManifest),
        }
        // 5. Check the signature of META-INF/zigbert.sf
        let mut rsa_file_buf: Vec<u8> = Vec::new();
        {
            let mut rsa_file = archive.by_name("META-INF/zigbert.rsa").unwrap();
            rsa_file
                .read_to_end(&mut rsa_file_buf)
                .map_err(|_| ZipVerificationError::InvalidZip)?;
        }
        let mut sf_file_buf: Vec<u8> = Vec::new();
        let mut sf_file = archive.by_name("META-INF/zigbert.sf").unwrap();
        sf_file
            .read_to_end(&mut sf_file_buf)
            .map_err(|_| ZipVerificationError::InvalidZip)?;
        let root_cert = CertificateType::from(cert_type).as_vec();
        sig_verification::verify(&rsa_file_buf, &sf_file_buf, &root_cert)?;
    } else {
        return Err(ZipVerificationError::InvalidManifest);
    }
    Ok(())
}
pub fn verify_zip < P : AsRef < Path > > ( path : P , cert_type : & str ) -> Result < ( ) , ZipVerificationError > { let file = File :: open ( path ) . map_err ( | _ | ZipVerificationError :: NoSuchFile ) ? ; let mut archive = ZipArchive :: new ( file ) . map_err ( | _ | ZipVerificationError :: InvalidZip ) ? ; // 1. Verify the presence of mandatory files in META-INF. Any other file will be // referenced in the hash list in META-INF/manifest.mf for name in [ " " , " " , " " , ] . iter ( ) { let _ = archive . by_name ( name ) . map_err ( | _ | ZipVerificationError :: MissingMetaFile ( ( * name ) . into ( ) ) ) ? ; } // 2. Get the parsed manifest. let mut content = Vec :: new ( ) ; { let mut file = archive . by_name ( " " ) . unwrap ( ) ; let _ = file . read_to_end ( & mut content ) . map_err ( | _ | ZipVerificationError :: InvalidZip ) ? ; } let mut cursor = Cursor :: new ( content ) ; if let Ok ( manifest ) = read_manifest ( & mut cursor ) { if manifest . version != " " { return Err ( ZipVerificationError :: InvalidManifest ) ; } // 3. Check that the list of files in the manifest matches the list of files in the zip: // - the total number of files in the zip must be manifest.entries + 3 (special the META-INF ones) // - every file listed in the manifest must exist. // - their hashes must match. if manifest . entries . len ( ) + 3 != archive . len ( ) { return Err ( ZipVerificationError :: InvalidFileList ) ; } for entry in manifest . entries { match archive . by_name ( & entry . name ) { Err ( _ ) => return Err ( ZipVerificationError :: InvalidFileList ) , Ok ( mut zipentry ) => { if let Some ( sha1 ) = entry . sha1 { check_entry_digest ( & mut zipentry , & digest :: SHA1_FOR_LEGACY_USE_ONLY , & sha1 , ) ? ; } else if let Some ( sha256 ) = entry . sha256 { check_entry_digest ( & mut zipentry , & digest :: SHA256 , & sha256 ) ? ; } } } } let mut sf_content = Vec :: new ( ) ; { let mut file = archive . by_name ( " " ) . unwrap ( ) ; let _ = file . read_to_end ( & mut sf_content ) . map_err ( | _ | ZipVerificationError :: InvalidZip ) ? ; } let mut sf_cursor = Cursor :: new ( sf_content ) ; // 4. Use the META-INF/zigbert.sf to check the hash of META-INF/manifest.mf match read_signature_manifest ( & mut sf_cursor ) { Ok ( manifest_hash ) => { check_entry_digest ( & mut archive . by_name ( " " ) . unwrap ( ) , & digest :: SHA1_FOR_LEGACY_USE_ONLY , & manifest_hash , ) ? ; } Err ( _ ) => return Err ( ZipVerificationError :: InvalidManifest ) , } // 5. Check the signature of META-INF/zigbert.sf let mut rsa_file_buf : Vec < u8 > = Vec :: new ( ) ; { let mut rsa_file = archive . by_name ( " " ) . unwrap ( ) ; rsa_file . read_to_end ( & mut rsa_file_buf ) . map_err ( | _ | ZipVerificationError :: InvalidZip ) ? ; } let mut sf_file_buf : Vec < u8 > = Vec :: new ( ) ; let mut sf_file = archive . by_name ( " " ) . unwrap ( ) ; sf_file . read_to_end ( & mut sf_file_buf ) . map_err ( | _ | ZipVerificationError :: InvalidZip ) ? ; let root_cert = CertificateType :: from ( cert_type ) . as_vec ( ) ; sig_verification :: verify ( & rsa_file_buf , & sf_file_buf , & root_cert ) ? ; } else { return Err ( ZipVerificationError :: InvalidManifest ) ; } Ok ( ( ) ) }
Verifies the hashes and signature of a zip file at the given path.
Verifies the hashes and signature of a zip file at the given path .
path
P
cert_type
&str