1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Windows Authenticode Portable Executable Signature Format
//!
//! Authenticode is a digital signature format that is used to determine the origin and integrity of
//! software binaries. Authenticode is based on Public-Key Cryptography Standards (PKCS) #7 signed
//! data and X.509 certificates to bind an Authenticode-signed binary to the identity of a software
//! publisher.
//!
//! Reference: [Windows Authenticode Portable Executable Signature Format] (http://msdn.microsoft.com/en-US/windows/hardware/gg463183)
//! **NOTE**: the document differs from the actual implementation. This crate contains the structures used in actual signing.
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Neg};

use rasn::types::{
    Any, BitString, BmpString, ConstOid, Ia5String, ObjectIdentifier, OctetString, Oid,
};
use rasn::{AsnType, Decode, Encode};
use rasn_pkix::AlgorithmIdentifier;

pub const SPC_INDIRECT_DATA_OBJID: ConstOid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_INDIRECT_DATA_OBJID;
pub const SPC_PE_IMAGE_DATA_OBJID: ConstOid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_PE_IMAGE_DATA_OBJID;
pub const SPC_SP_OPUS_INFO_OBJID: ConstOid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_SP_OPUS_INFO_OBJID;
pub const SPC_STATEMENT_TYPE_OBJID: ConstOid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_STATEMENT_TYPE_OBJID;
pub const SPC_CAB_DATA_OBJID: ConstOid =
    Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_CAB_DATA_OBJID;
pub const SPC_SIPINFO_OBJID: ConstOid =
    Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_SIPINFO_OBJID;
pub const SPC_PE_IMAGE_PAGE_HASHES_V1: ConstOid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_PE_IMAGE_PAGE_HASHES_V1;
pub const SPC_PE_IMAGE_PAGE_HASHES_V2: ConstOid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_PE_IMAGE_PAGE_HASHES_V2;
pub const SPC_NESTED_SIGNATURE_OBJID: ConstOid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_NESTED_SIGNATURE_OBJID;
pub const SPC_TIME_STAMP_REQUEST_OBJID: ConstOid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_TIME_STAMP_REQUEST_OBJID;
pub const SPC_RFC3161_OBJID: ConstOid =
    Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES_MICROSOFT_SPC_RFC3161_OBJID;

pub const SPC_CLASS_UUID: OctetString = OctetString::from_static(&[
    0xa6, 0xb5, 0x86, 0xd5, 0xb4, 0xa1, 0x24, 0x66, 0xae, 0x05, 0xa2, 0x17, 0xda, 0x8e, 0x60, 0xd6,
]);

pub type SpcUuid = OctetString;

/// An Authenticode signature's ContentInfo structure contains several structures that in turn contain
/// the file's hash value, page hash values (if present), the file description, and various optional or legacy
/// ASN.1 fields. The root structure is SpcIndirectDataContent.
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpcIndirectDataContent {
    pub data: SpcAttributeTypeAndOptionalValue,
    pub message_digest: DigestInfo,
}

/// The SpcAttributeTypeAndOptionalValue structure has two fields, which are set for an
/// Authenticode-signed PE file.
/// The attribute_type is set to SPC_PE_IMAGE_DATAOBJ OID (1.3.6.1.4.1.311.2.1.15)
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpcAttributeTypeAndOptionalValue {
    pub attribute_type: ObjectIdentifier,
    pub value: Option<Any>,
}

/// The DigestInfo structure defines the digest algorithm and data
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DigestInfo {
    pub digest_algorithm: AlgorithmIdentifier,
    pub digest: OctetString,
}

/// The SpcPeImageData structure specifies which portions of the Windows PE file are hashed.
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpcPeImageData {
    pub flags: SpcPeImageFlags,
    #[rasn(tag(explicit(0)))]
    pub file: Option<SpcLink>,
}

/// Flags specify which portions of the Windows PE file are hashed.
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[rasn(delegate)]
pub struct SpcPeImageFlags(pub BitString);

impl SpcPeImageFlags {
    pub fn include_resources() -> Self {
        Self(BitString::from_element(0))
    }

    pub fn include_debug_info() -> Self {
        Self(BitString::from_element(1))
    }

    pub fn include_import_address_table() -> Self {
        Self(BitString::from_element(2))
    }
}

impl BitOr for SpcPeImageFlags {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self::Output {
        Self(self.0 | rhs.0)
    }
}

impl BitOrAssign for SpcPeImageFlags {
    fn bitor_assign(&mut self, rhs: Self) {
        self.0 |= rhs.0;
    }
}

impl BitAnd for SpcPeImageFlags {
    type Output = Self;

    fn bitand(self, rhs: Self) -> Self::Output {
        Self(self.0 & rhs.0)
    }
}

impl BitAndAssign for SpcPeImageFlags {
    fn bitand_assign(&mut self, rhs: Self) {
        self.0 &= rhs.0;
    }
}

impl Neg for SpcPeImageFlags {
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self(!self.0)
    }
}

/// SPCLink originally contained information that describes the software publisher
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[rasn(choice)]
pub enum SpcLink {
    #[rasn(tag(0))]
    Url(Ia5String),
    #[rasn(tag(1))]
    Moniker(SpcSerializedObject),
    #[rasn(tag(explicit(2)))]
    File(SpcString),
}

/// SpcString is either Unicode or ASCII string
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[rasn(choice)]
pub enum SpcString {
    #[rasn(tag(0))]
    Unicode(BmpString),
    #[rasn(tag(1))]
    Ascii(Ia5String),
}

/// SpcSerializedObject contains a binary structure with page hashes
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpcSerializedObject {
    pub class_id: SpcUuid,
    pub serialized_data: OctetString,
}

/// This structure is present in SignerInfo authenticated attributes.
/// It is identified by SPC_SP_OPUS_INFO_OBJID (1.3.6.1.4.1.311.2.1.12)
#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpcSpOpusInfo {
    #[rasn(tag(explicit(0)))]
    pub program_name: Option<SpcString>,
    #[rasn(tag(explicit(1)))]
    pub more_info: Option<SpcLink>,
}