File: Verification\CabSecurityInfoProvider.cs
Web Access
Project: src\src\SignCheck\Microsoft.SignCheck\Microsoft.DotNet.SignCheckLibrary.csproj (Microsoft.DotNet.SignCheckLibrary)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.IO;
using System.Security.Cryptography.Pkcs;
 
namespace Microsoft.SignCheck.Verification
{
    /// <summary>
    /// Reads digital signature information from Cabinet (.cab) files.
    /// Signed CAB files store their PKCS#7 Authenticode signature at an offset
    /// specified in the per-cabinet reserved area of the cabinet header.
    /// MSU files are also CAB-format files and use the same signing mechanism.
    /// </summary>
    public class CabSecurityInfoProvider : ISecurityInfoProvider
    {
        // Cabinet file signature: 'MSCF' (0x4D, 0x53, 0x43, 0x46)
        // Read as little-endian uint32: 0x4643534D
        private const uint CabinetSignature = 0x4643534D;
 
        // Cabinet header flag indicating reserved fields are present
        private const ushort CfhdrReservePresent = 0x0004;
 
        // Minimum header size: 36 bytes standard header + 4 bytes reserve fields
        private const int MinHeaderSize = 40;
 
        public SignedCms ReadSecurityInfo(string path)
        {
            try
            {
                using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (var reader = new BinaryReader(fs))
                {
                    if (fs.Length < MinHeaderSize)
                    {
                        return null;
                    }
 
                    // CFHEADER fields
                    uint signature = reader.ReadUInt32();    // offset 0: signature
                    if (signature != CabinetSignature)
                    {
                        return null;
                    }
 
                    reader.ReadUInt32();                     // offset 4: reserved1
                    reader.ReadUInt32();                     // offset 8: cbCabinet
                    reader.ReadUInt32();                     // offset 12: reserved2
                    reader.ReadUInt32();                     // offset 16: coffFiles
                    reader.ReadUInt32();                     // offset 20: reserved3
                    reader.ReadByte();                       // offset 24: versionMinor
                    reader.ReadByte();                       // offset 25: versionMajor
                    reader.ReadUInt16();                     // offset 26: cFolders
                    reader.ReadUInt16();                     // offset 28: cFiles
                    ushort flags = reader.ReadUInt16();      // offset 30: flags
                    reader.ReadUInt16();                     // offset 32: setID
                    reader.ReadUInt16();                     // offset 34: iCabinet
 
                    if ((flags & CfhdrReservePresent) == 0)
                    {
                        // No reserved area — file is not signed
                        return null;
                    }
 
                    // CFRESERVE fields
                    ushort cbCFHeader = reader.ReadUInt16(); // offset 36: per-cabinet reserved size
                    reader.ReadByte();                       // offset 38: cbCFFolder
                    reader.ReadByte();                       // offset 39: cbCFData
 
                    // The per-cabinet reserved area for signed CABs contains:
                    //   uint32 signatureOffset - file offset to the PKCS#7 signature
                    //   uint32 signatureSize   - size of the PKCS#7 signature
                    if (cbCFHeader < 8)
                    {
                        return null;
                    }
 
                    uint signatureOffset = reader.ReadUInt32();
                    uint signatureSize = reader.ReadUInt32();
 
                    if (signatureOffset == 0 || signatureSize == 0)
                    {
                        return null;
                    }
 
                    if (signatureOffset + signatureSize > (uint)fs.Length)
                    {
                        return null;
                    }
 
                    // Read the PKCS#7 signature data
                    fs.Position = signatureOffset;
                    byte[] signatureBytes = new byte[signatureSize];
                    fs.ReadExactly(signatureBytes);
 
                    var signedCms = new SignedCms();
                    signedCms.Decode(signatureBytes);
                    return signedCms;
                }
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}