Skip to content

Commit 7a11dd4

Browse files
sarroutbiclaude
authored andcommitted
Accept evidence handling structures null entries
Update ImaLog and UefiLog structures to handle null entries field: - Change entries field from String to Option<String> in both structures - Update serialization/deserialization logic to handle null values - Modify entry count calculation for ImaLog to handle None entries - Add comprehensive tests for null entries scenarios - Update context_info.rs to wrap entries in Some() when creating evidence This change improves robustness when handling evidence data that may null entry fields, which can occur in certain attestation scenarios. Co-Authored-By: Claude <[email protected]> Signed-off-by: Sergio Arroutbi <[email protected]>
1 parent fb4bcdc commit 7a11dd4

File tree

2 files changed

+193
-31
lines changed

2 files changed

+193
-31
lines changed

keylime/src/context_info.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ impl ContextInfo {
522522
let entry_count = entries.lines().count();
523523
Ok(EvidenceData::ImaLog {
524524
entry_count,
525-
entries,
525+
entries: Some(entries),
526526
meta: None,
527527
})
528528
}
@@ -551,7 +551,7 @@ impl ContextInfo {
551551
};
552552

553553
Ok(EvidenceData::UefiLog {
554-
entries: content,
554+
entries: Some(content),
555555
meta: None,
556556
})
557557
}

keylime/src/structures/evidence_handling.rs

Lines changed: 191 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ pub enum EvidenceData {
6060
meta: Option<JsonValue>,
6161
},
6262
UefiLog {
63-
entries: String,
63+
entries: Option<String>,
6464
#[serde(skip_serializing_if = "Option::is_none")]
6565
meta: Option<JsonValue>,
6666
},
6767
ImaLog {
6868
entry_count: usize,
69-
entries: String,
69+
entries: Option<String>,
7070
#[serde(skip_serializing_if = "Option::is_none")]
7171
meta: Option<JsonValue>,
7272
},
@@ -110,10 +110,19 @@ impl TryFrom<JsonValue> for EvidenceData {
110110
as usize;
111111
let entries = value
112112
.get("entries")
113-
.ok_or_else(|| "Missing entries field".to_string())?
114-
.as_str()
115-
.ok_or_else(|| "Invalid entries field".to_string())?
116-
.to_string();
113+
.ok_or_else(|| "Missing entries field".to_string())?;
114+
let entries = if entries.is_null() {
115+
None
116+
} else {
117+
Some(
118+
entries
119+
.as_str()
120+
.ok_or_else(|| {
121+
"Invalid entries field".to_string()
122+
})?
123+
.to_string(),
124+
)
125+
};
117126
let meta = value.get("meta").cloned();
118127
return Ok(EvidenceData::ImaLog {
119128
entry_count,
@@ -123,19 +132,21 @@ impl TryFrom<JsonValue> for EvidenceData {
123132
} else {
124133
return Err("Invalid entry_count field".to_string());
125134
}
126-
} else if let Some(entries) = value.get("entries") {
127-
if entries.is_string() {
128-
let entries = value
129-
.get("entries")
130-
.unwrap() //#[allow_ci]
131-
.as_str()
132-
.unwrap() //#[allow_ci]
133-
.to_string();
134-
let meta = value.get("meta").cloned();
135-
return Ok(EvidenceData::UefiLog { entries, meta });
135+
} else if let Some(entries_value) = value.get("entries") {
136+
let entries = if entries_value.is_null() {
137+
None
138+
} else if entries_value.is_string() {
139+
Some(
140+
entries_value
141+
.as_str()
142+
.ok_or_else(|| "Invalid entries field".to_string())?
143+
.to_string(),
144+
)
136145
} else {
137146
return Err("Invalid entries field".to_string());
138-
}
147+
};
148+
let meta = value.get("meta").cloned();
149+
return Ok(EvidenceData::UefiLog { entries, meta });
139150
};
140151
Err("Failed to deserialize EvidenceData".to_string())
141152
}
@@ -213,7 +224,8 @@ impl From<EvidenceData> for EvidenceCollected {
213224
},
214225
EvidenceData::ImaLog { entries, meta, .. } => {
215226
// Count the number of entries (lines)
216-
let entry_count = entries.lines().count();
227+
let entry_count =
228+
entries.as_ref().map_or(0, |e| e.lines().count());
217229
EvidenceCollected {
218230
evidence_class: "log".to_string(),
219231
evidence_type: "ima_log".to_string(),
@@ -322,7 +334,7 @@ mod tests {
322334
// Test ImaLog conversion
323335
let ima_evidence = EvidenceData::ImaLog {
324336
entry_count: 0, // This should be recalculated
325-
entries: "line1\nline2\nline3".to_string(),
337+
entries: Some("line1\nline2\nline3".to_string()),
326338
meta: None,
327339
};
328340
let ima_collected: EvidenceCollected = ima_evidence.into();
@@ -335,21 +347,21 @@ mod tests {
335347
} = ima_collected.data
336348
{
337349
assert_eq!(entry_count, 3); // Should be recalculated from lines
338-
assert_eq!(entries, "line1\nline2\nline3");
350+
assert_eq!(entries, Some("line1\nline2\nline3".to_string()));
339351
} else {
340352
panic!("Expected ImaLog"); //#[allow_ci]
341353
}
342354

343355
// Test UefiLog conversion
344356
let uefi_evidence = EvidenceData::UefiLog {
345-
entries: "uefi_entries".to_string(),
357+
entries: Some("uefi_entries".to_string()),
346358
meta: None,
347359
};
348360
let uefi_collected: EvidenceCollected = uefi_evidence.into();
349361
assert_eq!(uefi_collected.evidence_class, "log");
350362
assert_eq!(uefi_collected.evidence_type, "uefi_log");
351363
if let EvidenceData::UefiLog { entries, .. } = uefi_collected.data {
352-
assert_eq!(entries, "uefi_entries");
364+
assert_eq!(entries, Some("uefi_entries".to_string()));
353365
} else {
354366
panic!("Expected UefiLog"); //#[allow_ci]
355367
}
@@ -371,7 +383,7 @@ mod tests {
371383
};
372384

373385
let uefi_evidence_data = EvidenceData::UefiLog {
374-
entries: "uefi_log_entries".to_string(),
386+
entries: Some("uefi_log_entries".to_string()),
375387
meta: None,
376388
};
377389
let uefi_evidence_collected = EvidenceCollected {
@@ -382,7 +394,7 @@ mod tests {
382394

383395
let ima_evidence_data = EvidenceData::ImaLog {
384396
entry_count: 95,
385-
entries: "ima_log_entries".to_string(),
397+
entries: Some("ima_log_entries".to_string()),
386398
meta: None,
387399
};
388400
let ima_evidence_collected = EvidenceCollected {
@@ -517,7 +529,10 @@ mod tests {
517529
if let EvidenceData::UefiLog { entries, .. } =
518530
&deserialized.data.attributes.evidence_collected[1].data
519531
{
520-
assert_eq!(entries, "uefi_log_entries_deserialized");
532+
assert_eq!(
533+
entries,
534+
&Some("uefi_log_entries_deserialized".to_string())
535+
);
521536
} else {
522537
panic!("Expected UefiLog"); //#[allow_ci]
523538
}
@@ -536,7 +551,10 @@ mod tests {
536551
} = &deserialized.data.attributes.evidence_collected[2].data
537552
{
538553
assert_eq!(*entry_count, 96);
539-
assert_eq!(entries, "ima_log_entries_deserialized");
554+
assert_eq!(
555+
entries,
556+
&Some("ima_log_entries_deserialized".to_string())
557+
);
540558
} else {
541559
panic!("Expected ImaLog"); //#[allow_ci]
542560
}
@@ -955,7 +973,7 @@ mod tests {
955973
)),
956974
),
957975
data: EvidenceData::UefiLog {
958-
entries: "uefi_log_entries".to_string(),
976+
entries: Some("uefi_log_entries".to_string()),
959977
meta: None,
960978
},
961979
},
@@ -980,7 +998,7 @@ mod tests {
980998
)),
981999
data: EvidenceData::ImaLog {
9821000
entry_count: 96,
983-
entries: "ima_log_entries".to_string(),
1001+
entries: Some("ima_log_entries".to_string()),
9841002
meta: None,
9851003
},
9861004
},
@@ -1441,7 +1459,7 @@ mod tests {
14411459
if let EvidenceData::UefiLog { entries, .. } =
14421460
&deserialized.data.attributes.evidence[1].data
14431461
{
1444-
assert_eq!(entries, "uefi_log_entries");
1462+
assert_eq!(entries, &Some("uefi_log_entries".to_string()));
14451463
} else {
14461464
panic!("Expected UefiLog"); //#[allow_ci]
14471465
}
@@ -1475,4 +1493,148 @@ mod tests {
14751493
"2025-08-07 12:22:17.228706 UTC"
14761494
);
14771495
} //serialize_evidence_handling_response
1496+
1497+
#[test]
1498+
fn deserialize_evidence_handling_request_null_entries_uefi() {
1499+
let json = r#"{
1500+
"data": {
1501+
"type": "attestation",
1502+
"attributes": {
1503+
"evidence_collected": [
1504+
{
1505+
"evidence_class": "log",
1506+
"evidence_type": "uefi_log",
1507+
"data": {
1508+
"entries": null
1509+
}
1510+
}
1511+
]
1512+
}
1513+
}
1514+
}"#;
1515+
let deserialized: EvidenceHandlingRequest =
1516+
serde_json::from_str(json).unwrap(); //#[allow_ci]
1517+
1518+
assert_eq!(deserialized.data.data_type, "attestation");
1519+
assert_eq!(deserialized.data.attributes.evidence_collected.len(), 1);
1520+
assert_eq!(
1521+
deserialized.data.attributes.evidence_collected[0].evidence_class,
1522+
"log"
1523+
);
1524+
assert_eq!(
1525+
deserialized.data.attributes.evidence_collected[0].evidence_type,
1526+
"uefi_log"
1527+
);
1528+
if let EvidenceData::UefiLog { entries, .. } =
1529+
&deserialized.data.attributes.evidence_collected[0].data
1530+
{
1531+
assert!(entries.is_none());
1532+
} else {
1533+
panic!("Expected UefiLog"); //#[allow_ci]
1534+
}
1535+
}
1536+
1537+
#[test]
1538+
fn deserialize_evidence_handling_request_null_entries_ima() {
1539+
let json = r#"{
1540+
"data": {
1541+
"type": "attestation",
1542+
"attributes": {
1543+
"evidence_collected": [
1544+
{
1545+
"evidence_class": "log",
1546+
"evidence_type": "ima_log",
1547+
"data": {
1548+
"entries": null,
1549+
"entry_count": 0
1550+
}
1551+
}
1552+
]
1553+
}
1554+
}
1555+
}"#;
1556+
let deserialized: EvidenceHandlingRequest =
1557+
serde_json::from_str(json).unwrap(); //#[allow_ci]
1558+
1559+
assert_eq!(deserialized.data.data_type, "attestation");
1560+
assert_eq!(deserialized.data.attributes.evidence_collected.len(), 1);
1561+
assert_eq!(
1562+
deserialized.data.attributes.evidence_collected[0].evidence_class,
1563+
"log"
1564+
);
1565+
assert_eq!(
1566+
deserialized.data.attributes.evidence_collected[0].evidence_type,
1567+
"ima_log"
1568+
);
1569+
if let EvidenceData::ImaLog {
1570+
entries,
1571+
entry_count,
1572+
..
1573+
} = &deserialized.data.attributes.evidence_collected[0].data
1574+
{
1575+
assert!(entries.is_none());
1576+
assert_eq!(*entry_count, 0);
1577+
} else {
1578+
panic!("Expected ImaLog"); //#[allow_ci]
1579+
}
1580+
}
1581+
1582+
#[test]
1583+
fn serialize_evidence_data_null_entries() {
1584+
// Test serialization of UefiLog with null entries
1585+
let uefi_evidence = EvidenceData::UefiLog {
1586+
entries: None,
1587+
meta: None,
1588+
};
1589+
let serialized = serde_json::to_string(&uefi_evidence).unwrap(); //#[allow_ci]
1590+
assert!(serialized.contains("\"entries\":null"));
1591+
1592+
// Test serialization of ImaLog with null entries
1593+
let ima_evidence = EvidenceData::ImaLog {
1594+
entry_count: 0,
1595+
entries: None,
1596+
meta: None,
1597+
};
1598+
let serialized = serde_json::to_string(&ima_evidence).unwrap(); //#[allow_ci]
1599+
assert!(serialized.contains("\"entries\":null"));
1600+
assert!(serialized.contains("\"entry_count\":0"));
1601+
}
1602+
1603+
#[test]
1604+
fn evidence_data_to_evidence_collected_null_entries() {
1605+
// Test ImaLog with null entries conversion
1606+
let ima_evidence = EvidenceData::ImaLog {
1607+
entry_count: 0,
1608+
entries: None,
1609+
meta: None,
1610+
};
1611+
let ima_collected: EvidenceCollected = ima_evidence.into();
1612+
assert_eq!(ima_collected.evidence_class, "log");
1613+
assert_eq!(ima_collected.evidence_type, "ima_log");
1614+
if let EvidenceData::ImaLog {
1615+
entry_count,
1616+
entries,
1617+
..
1618+
} = ima_collected.data
1619+
{
1620+
assert_eq!(entry_count, 0); // Should be 0 for null entries
1621+
assert!(entries.is_none());
1622+
} else {
1623+
panic!("Expected ImaLog"); //#[allow_ci]
1624+
}
1625+
1626+
// Test UefiLog with null entries conversion
1627+
let uefi_evidence = EvidenceData::UefiLog {
1628+
entries: None,
1629+
meta: None,
1630+
};
1631+
let uefi_collected: EvidenceCollected = uefi_evidence.into();
1632+
assert_eq!(uefi_collected.evidence_class, "log");
1633+
assert_eq!(uefi_collected.evidence_type, "uefi_log");
1634+
if let EvidenceData::UefiLog { entries, .. } = uefi_collected.data {
1635+
assert!(entries.is_none());
1636+
} else {
1637+
panic!("Expected UefiLog"); //#[allow_ci]
1638+
}
1639+
}
14781640
}

0 commit comments

Comments
 (0)