or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-storage.mdequivalence.mdindex.mdmarkings.mdobject-creation.mdpattern-matching.mdrelationships.mdstix-domain-objects.mdstix-observables.mdutilities.mdversioning.md

utilities.mddocs/

0

# Utilities and Type Checking

1

2

Utility functions for working with STIX objects including type checking, timestamp handling, object deduplication, and specification version detection.

3

4

## Capabilities

5

6

### Type Checking Functions

7

8

Functions to identify and validate STIX object types.

9

10

```python { .api }

11

def is_sdo(value, stix_version="2.1"):

12

"""

13

Check if value is a STIX Domain Object.

14

15

Parameters:

16

- value: Object to check (STIX object, dict, or string)

17

- stix_version (str): STIX specification version ("2.0" or "2.1")

18

19

Returns:

20

bool: True if value is an SDO, False otherwise

21

"""

22

23

def is_sco(value, stix_version="2.1"):

24

"""

25

Check if value is a STIX Cyber Observable Object.

26

27

Parameters:

28

- value: Object to check (STIX object, dict, or string)

29

- stix_version (str): STIX specification version ("2.0" or "2.1")

30

31

Returns:

32

bool: True if value is an SCO, False otherwise

33

"""

34

35

def is_sro(value, stix_version="2.1"):

36

"""

37

Check if value is a STIX Relationship Object.

38

39

Parameters:

40

- value: Object to check (STIX object, dict, or string)

41

- stix_version (str): STIX specification version ("2.0" or "2.1")

42

43

Returns:

44

bool: True if value is an SRO, False otherwise

45

"""

46

47

def is_object(value, stix_version="2.1"):

48

"""

49

Check if value is any STIX object (SDO, SRO, or marking).

50

51

Parameters:

52

- value: Object to check (STIX object, dict, or string)

53

- stix_version (str): STIX specification version ("2.0" or "2.1")

54

55

Returns:

56

bool: True if value is a STIX object, False otherwise

57

"""

58

59

def is_marking(value, stix_version="2.1"):

60

"""

61

Check if value is a STIX marking definition.

62

63

Parameters:

64

- value: Object to check (STIX object, dict, or string)

65

- stix_version (str): STIX specification version ("2.0" or "2.1")

66

67

Returns:

68

bool: True if value is a marking definition, False otherwise

69

"""

70

71

def is_stix_type(value, stix_version="2.1", *types):

72

"""

73

Check if value is one of the specified STIX types.

74

75

Parameters:

76

- value: Object to check

77

- stix_version (str): STIX specification version

78

- *types: Variable number of STIXTypeClass values to check against

79

80

Returns:

81

bool: True if value matches any of the specified types

82

"""

83

```

84

85

Usage examples:

86

87

```python

88

from stix2 import is_sdo, is_sco, is_sro, is_object, is_marking

89

from stix2 import Indicator, Malware, File, Relationship, MarkingDefinition

90

91

# Create test objects

92

indicator = Indicator(

93

name="Test Indicator",

94

indicator_types=["malicious-activity"],

95

pattern_type="stix",

96

pattern="[file:hashes.MD5 = 'abc123']"

97

)

98

99

malware = Malware(

100

name="Test Malware",

101

malware_types=["trojan"]

102

)

103

104

file_obj = File(

105

hashes={"MD5": "abc123"},

106

name="test.exe"

107

)

108

109

relationship = Relationship(

110

relationship_type="indicates",

111

source_ref=indicator.id,

112

target_ref=malware.id

113

)

114

115

marking = MarkingDefinition(

116

definition_type="statement",

117

definition={"statement": "Internal Use Only"}

118

)

119

120

# Type checking

121

print(f"Indicator is SDO: {is_sdo(indicator)}") # True

122

print(f"Malware is SDO: {is_sdo(malware)}") # True

123

print(f"File is SDO: {is_sdo(file_obj)}") # False

124

125

print(f"File is SCO: {is_sco(file_obj)}") # True

126

print(f"Indicator is SCO: {is_sco(indicator)}") # False

127

128

print(f"Relationship is SRO: {is_sro(relationship)}") # True

129

print(f"Indicator is SRO: {is_sro(indicator)}") # False

130

131

print(f"Marking is marking: {is_marking(marking)}") # True

132

print(f"Indicator is marking: {is_marking(indicator)}")# False

133

134

# Check any STIX object

135

print(f"Indicator is STIX object: {is_object(indicator)}") # True

136

print(f"File is STIX object: {is_object(file_obj)}") # True

137

print(f"Relationship is STIX object: {is_object(relationship)}")# True

138

139

# Check with dictionaries

140

indicator_dict = {

141

"type": "indicator",

142

"id": "indicator--12345678-1234-1234-1234-123456789012",

143

"name": "Test Indicator"

144

}

145

print(f"Dict is SDO: {is_sdo(indicator_dict)}") # True

146

147

# Check with type strings

148

print(f"'indicator' is SDO: {is_sdo('indicator')}") # True

149

print(f"'file' is SCO: {is_sco('file')}") # True

150

print(f"'relationship' is SRO: {is_sro('relationship')}")# True

151

```

152

153

### Timestamp Utilities

154

155

Functions for working with STIX timestamps and datetime objects.

156

157

```python { .api }

158

def get_timestamp():

159

"""

160

Get current timestamp in STIX format.

161

162

Returns:

163

str: Current timestamp in STIX format (ISO 8601)

164

"""

165

166

def format_datetime(dttm):

167

"""

168

Format datetime object to STIX timestamp string.

169

170

Parameters:

171

- dttm (datetime): Datetime object to format

172

173

Returns:

174

str: Formatted timestamp string

175

"""

176

177

def parse_into_datetime(value, precision=None, allow_none=False):

178

"""

179

Parse string into datetime object with STIX-specific handling.

180

181

Parameters:

182

- value: String or datetime to parse

183

- precision (Precision): Timestamp precision level

184

- allow_none (bool): Allow None values

185

186

Returns:

187

STIXdatetime: Parsed datetime object

188

189

Raises:

190

ValueError: If timestamp format is invalid

191

"""

192

193

class STIXdatetime:

194

"""

195

STIX-specific datetime class with precision handling.

196

197

Inherits from datetime.datetime with additional STIX-specific

198

formatting and precision methods.

199

"""

200

201

class Precision:

202

"""

203

Enumeration of timestamp precision levels.

204

205

Values:

206

- YEAR

207

- MONTH

208

- DAY

209

- HOUR

210

- MINUTE

211

- SECOND

212

- MILLISECOND

213

"""

214

```

215

216

Usage examples:

217

218

```python

219

from stix2 import get_timestamp, format_datetime, parse_into_datetime, STIXdatetime

220

from datetime import datetime

221

222

# Get current timestamp in STIX format

223

current_time = get_timestamp()

224

print(f"Current STIX timestamp: {current_time}")

225

# Output: "2021-04-23T10:30:45.123Z"

226

227

# Format datetime object

228

dt = datetime(2021, 4, 23, 10, 30, 45, 123000)

229

stix_formatted = format_datetime(dt)

230

print(f"Formatted datetime: {stix_formatted}")

231

# Output: "2021-04-23T10:30:45.123Z"

232

233

# Parse timestamp strings

234

timestamp_str = "2021-04-23T10:30:45.123Z"

235

parsed_dt = parse_into_datetime(timestamp_str)

236

print(f"Parsed datetime: {parsed_dt}")

237

print(f"Type: {type(parsed_dt)}") # STIXdatetime

238

239

# Parse with different precision

240

from stix2.utils import Precision

241

242

year_precision = parse_into_datetime("2021", precision=Precision.YEAR)

243

day_precision = parse_into_datetime("2021-04-23", precision=Precision.DAY)

244

245

print(f"Year precision: {year_precision}") # 2021-01-01T00:00:00.000Z

246

print(f"Day precision: {day_precision}") # 2021-04-23T00:00:00.000Z

247

248

# STIX datetime usage

249

stix_dt = STIXdatetime(2021, 4, 23, 10, 30, 45, 123000)

250

print(f"STIX datetime: {stix_dt}")

251

252

# Parse various timestamp formats

253

timestamps = [

254

"2021-04-23T10:30:45Z",

255

"2021-04-23T10:30:45.123Z",

256

"2021-04-23T10:30:45+00:00",

257

"2021-04-23 10:30:45"

258

]

259

260

for ts in timestamps:

261

try:

262

parsed = parse_into_datetime(ts)

263

print(f"{ts} -> {parsed}")

264

except ValueError as e:

265

print(f"{ts} -> Error: {e}")

266

```

267

268

### Object Utilities

269

270

Utilities for working with STIX objects and their properties.

271

272

```python { .api }

273

def deduplicate(stix_obj_list):

274

"""

275

Remove duplicate STIX objects from a list.

276

277

Parameters:

278

- stix_obj_list (list): List of STIX objects

279

280

Returns:

281

list: List with duplicates removed (keeps most recent version)

282

"""

283

284

def get_class_hierarchy_names(obj):

285

"""

286

Get class hierarchy names for a STIX object.

287

288

Parameters:

289

- obj: STIX object

290

291

Returns:

292

list: List of class names in inheritance hierarchy

293

"""

294

295

def get_type_from_id(stix_id):

296

"""

297

Extract STIX type from STIX identifier.

298

299

Parameters:

300

- stix_id (str): STIX object identifier

301

302

Returns:

303

str: STIX object type or None if invalid ID

304

"""

305

306

def detect_spec_version(stix_dict):

307

"""

308

Detect STIX specification version from object dictionary.

309

310

Parameters:

311

- stix_dict (dict): STIX object as dictionary

312

313

Returns:

314

str: Detected STIX version ("2.0" or "2.1")

315

"""

316

317

def to_enum(value, enum_type, enum_default=None):

318

"""

319

Convert value to enumeration type with default fallback.

320

321

Parameters:

322

- value: Value to convert

323

- enum_type: Target enumeration type

324

- enum_default: Default value if conversion fails

325

326

Returns:

327

Enum value or default

328

"""

329

```

330

331

Usage examples:

332

333

```python

334

from stix2 import deduplicate, get_type_from_id, detect_spec_version

335

from stix2 import Indicator, new_version

336

337

# Create objects with duplicates

338

indicator_v1 = Indicator(

339

name="Test Indicator",

340

indicator_types=["malicious-activity"],

341

pattern_type="stix",

342

pattern="[file:hashes.MD5 = 'abc123']"

343

)

344

345

indicator_v2 = new_version(indicator_v1, confidence=85)

346

indicator_v3 = new_version(indicator_v2, confidence=95)

347

348

# Different indicator

349

other_indicator = Indicator(

350

name="Other Indicator",

351

indicator_types=["malicious-activity"],

352

pattern_type="stix",

353

pattern="[ip-addr:value = '192.168.1.1']"

354

)

355

356

# List with duplicates (multiple versions of same object)

357

object_list = [indicator_v1, indicator_v2, indicator_v3, other_indicator, indicator_v1]

358

359

# Remove duplicates (keeps most recent version)

360

deduplicated = deduplicate(object_list)

361

print(f"Original list: {len(object_list)} objects")

362

print(f"Deduplicated: {len(deduplicated)} objects")

363

364

# Should contain indicator_v3 (most recent) and other_indicator

365

for obj in deduplicated:

366

if obj.id == indicator_v1.id:

367

print(f"Kept version modified: {obj.modified}") # Should be v3

368

369

# Extract type from STIX ID

370

stix_id = "indicator--12345678-1234-1234-1234-123456789012"

371

obj_type = get_type_from_id(stix_id)

372

print(f"Type from ID: {obj_type}") # "indicator"

373

374

# Test various ID formats

375

test_ids = [

376

"indicator--12345678-1234-1234-1234-123456789012",

377

"malware--abcdef12-3456-7890-abcd-ef1234567890",

378

"relationship--fedcba98-7654-3210-fedc-ba9876543210",

379

"invalid-id-format"

380

]

381

382

for test_id in test_ids:

383

obj_type = get_type_from_id(test_id)

384

print(f"{test_id} -> {obj_type}")

385

386

# Detect STIX specification version

387

stix_2_0_dict = {

388

"type": "indicator",

389

"id": "indicator--12345678-1234-1234-1234-123456789012",

390

"created": "2021-04-23T10:30:00.000Z",

391

"modified": "2021-04-23T10:30:00.000Z",

392

"labels": ["malicious-activity"],

393

"pattern": "[file:hashes.MD5 = 'abc123']"

394

}

395

396

stix_2_1_dict = {

397

"type": "indicator",

398

"spec_version": "2.1",

399

"id": "indicator--12345678-1234-1234-1234-123456789012",

400

"created": "2021-04-23T10:30:00.000Z",

401

"modified": "2021-04-23T10:30:00.000Z",

402

"indicator_types": ["malicious-activity"],

403

"pattern_type": "stix",

404

"pattern": "[file:hashes.MD5 = 'abc123']"

405

}

406

407

version_2_0 = detect_spec_version(stix_2_0_dict)

408

version_2_1 = detect_spec_version(stix_2_1_dict)

409

410

print(f"First dict version: {version_2_0}") # "2.0"

411

print(f"Second dict version: {version_2_1}") # "2.1"

412

413

# Class hierarchy inspection

414

hierarchy = get_class_hierarchy_names(indicator_v1)

415

print(f"Indicator class hierarchy: {hierarchy}")

416

```

417

418

### Advanced Type Checking

419

420

More sophisticated type checking and classification utilities.

421

422

```python

423

from stix2.utils import STIXTypeClass, is_stix_type

424

425

# STIXTypeClass enumeration values

426

print("Available STIX type classes:")

427

for type_class in STIXTypeClass:

428

print(f" - {type_class.name}: {type_class.value}")

429

430

# Check specific type classes

431

print(f"Indicator is SDO: {is_stix_type(indicator, '2.1', STIXTypeClass.SDO)}")

432

print(f"File is SCO: {is_stix_type(file_obj, '2.1', STIXTypeClass.SCO)}")

433

print(f"Relationship is SRO: {is_stix_type(relationship, '2.1', STIXTypeClass.SRO)}")

434

435

# Check multiple type classes

436

is_domain_or_relationship = is_stix_type(

437

indicator,

438

'2.1',

439

STIXTypeClass.SDO,

440

STIXTypeClass.SRO

441

)

442

print(f"Indicator is SDO or SRO: {is_domain_or_relationship}") # True

443

444

# Custom type classification function

445

def classify_stix_object(obj, version="2.1"):

446

"""Classify STIX object into detailed categories."""

447

if is_sdo(obj, version):

448

obj_type = obj.type if hasattr(obj, 'type') else str(obj)

449

450

threat_objects = ['threat-actor', 'intrusion-set', 'campaign']

451

malware_objects = ['malware', 'tool']

452

indicator_objects = ['indicator', 'observed-data']

453

target_objects = ['identity', 'location', 'infrastructure']

454

context_objects = ['attack-pattern', 'course-of-action', 'vulnerability']

455

456

if obj_type in threat_objects:

457

return "Threat Intelligence"

458

elif obj_type in malware_objects:

459

return "Malware/Tools"

460

elif obj_type in indicator_objects:

461

return "Indicators/Observables"

462

elif obj_type in target_objects:

463

return "Targets/Assets"

464

elif obj_type in context_objects:

465

return "Context/Mitigation"

466

else:

467

return "Other SDO"

468

469

elif is_sco(obj, version):

470

return "Cyber Observable"

471

elif is_sro(obj, version):

472

return "Relationship"

473

elif is_marking(obj, version):

474

return "Marking Definition"

475

else:

476

return "Unknown"

477

478

# Classify objects

479

test_objects = [indicator, malware, file_obj, relationship, marking]

480

for obj in test_objects:

481

classification = classify_stix_object(obj)

482

obj_name = getattr(obj, 'name', getattr(obj, 'type', str(obj)))

483

print(f"{obj_name}: {classification}")

484

```

485

486

### Confidence Scales

487

488

Functions for converting between different confidence scale representations. STIX 2.1 supports multiple confidence scales, and these functions provide standardized conversions between common scale formats.

489

490

```python { .api }

491

def none_low_med_high_to_value(scale_value):

492

"""

493

Transform string value from None/Low/Med/High scale to integer.

494

495

Parameters:

496

- scale_value (str): Scale value ("None", "Low", "Med", "High")

497

498

Returns:

499

int: Confidence value (0=None, 15=Low, 50=Med, 85=High)

500

501

Raises:

502

ValueError: If scale_value is not recognized

503

"""

504

505

def value_to_none_low_medium_high(confidence_value):

506

"""

507

Transform integer confidence value to None/Low/Med/High scale.

508

509

Parameters:

510

- confidence_value (int): Integer value between 0-100

511

512

Returns:

513

str: Scale string (0="None", 1-29="Low", 30-69="Med", 70-100="High")

514

515

Raises:

516

ValueError: If confidence_value is out of bounds

517

"""

518

519

def zero_ten_to_value(scale_value):

520

"""

521

Transform string value from 0-10 scale to confidence integer.

522

523

Parameters:

524

- scale_value (str): Scale value from "0" to "10"

525

526

Returns:

527

int: Confidence value (0-100, mapped from 0-10 scale)

528

529

Raises:

530

ValueError: If scale_value is not valid 0-10 string

531

"""

532

533

def value_to_zero_ten(confidence_value):

534

"""

535

Transform integer confidence value to 0-10 scale.

536

537

Parameters:

538

- confidence_value (int): Integer value between 0-100

539

540

Returns:

541

str: Scale string from "0" to "10"

542

543

Raises:

544

ValueError: If confidence_value is out of bounds

545

"""

546

547

def admiralty_credibility_to_value(scale_value):

548

"""

549

Transform Admiralty Credibility scale to confidence integer.

550

551

Parameters:

552

- scale_value (str): Admiralty scale ("A" through "F")

553

554

Returns:

555

int: Confidence value mapped from Admiralty scale

556

557

Raises:

558

ValueError: If scale_value is not valid Admiralty scale

559

"""

560

561

def value_to_admiralty_credibility(confidence_value):

562

"""

563

Transform confidence integer to Admiralty Credibility scale.

564

565

Parameters:

566

- confidence_value (int): Integer value between 0-100

567

568

Returns:

569

str: Admiralty scale value ("A" through "F")

570

571

Raises:

572

ValueError: If confidence_value is out of bounds

573

"""

574

```

575

576

Usage examples:

577

578

```python

579

from stix2.confidence.scales import (

580

none_low_med_high_to_value, value_to_none_low_medium_high,

581

zero_ten_to_value, value_to_zero_ten,

582

admiralty_credibility_to_value, value_to_admiralty_credibility

583

)

584

585

# None/Low/Med/High scale conversions

586

print("None/Low/Med/High Scale:")

587

scales = ["None", "Low", "Med", "High"]

588

for scale in scales:

589

value = none_low_med_high_to_value(scale)

590

print(f" {scale} -> {value}")

591

592

# Convert confidence values back to scale

593

confidence_values = [0, 15, 35, 50, 75, 85, 100]

594

print("\nConfidence to None/Low/Med/High:")

595

for conf in confidence_values:

596

try:

597

scale = value_to_none_low_medium_high(conf)

598

print(f" {conf} -> {scale}")

599

except ValueError as e:

600

print(f" {conf} -> Error: {e}")

601

602

# 0-10 scale conversions

603

print("\n0-10 Scale:")

604

for i in range(11):

605

str_scale = str(i)

606

value = zero_ten_to_value(str_scale)

607

print(f" {str_scale} -> {value}")

608

609

# Convert back to 0-10 scale

610

print("\nConfidence to 0-10 Scale:")

611

test_values = [0, 25, 50, 75, 100]

612

for conf in test_values:

613

try:

614

scale = value_to_zero_ten(conf)

615

print(f" {conf} -> {scale}")

616

except ValueError as e:

617

print(f" {conf} -> Error: {e}")

618

619

# Admiralty Credibility scale

620

print("\nAdmiralty Credibility Scale:")

621

admiralty_scales = ["A", "B", "C", "D", "E", "F"]

622

for scale in admiralty_scales:

623

try:

624

value = admiralty_credibility_to_value(scale)

625

print(f" {scale} -> {value}")

626

except ValueError as e:

627

print(f" {scale} -> Error: {e}")

628

629

# Practical usage in STIX objects

630

from stix2 import Indicator

631

632

# Create indicators with confidence from different scales

633

high_confidence = none_low_med_high_to_value("High") # 85

634

medium_confidence = zero_ten_to_value("5") # 50

635

low_confidence = value_to_none_low_medium_high(20) # "Low"

636

637

indicator_high = Indicator(

638

name="High Confidence Indicator",

639

indicator_types=["malicious-activity"],

640

pattern_type="stix",

641

pattern="[file:hashes.md5 = 'abc123']",

642

confidence=high_confidence

643

)

644

645

indicator_medium = Indicator(

646

name="Medium Confidence Indicator",

647

indicator_types=["malicious-activity"],

648

pattern_type="stix",

649

pattern="[ip-addr:value = '192.168.1.1']",

650

confidence=medium_confidence

651

)

652

653

print(f"\nHigh confidence indicator: {indicator_high.confidence}")

654

print(f"Medium confidence indicator: {indicator_medium.confidence}")

655

656

# Convert indicator confidence back to human-readable scales

657

high_scale = value_to_none_low_medium_high(indicator_high.confidence)

658

medium_scale = value_to_zero_ten(indicator_medium.confidence)

659

660

print(f"High confidence as scale: {high_scale}") # "High"

661

print(f"Medium confidence as 0-10: {medium_scale}") # "5"

662

663

# Error handling for invalid inputs

664

try:

665

invalid_scale = none_low_med_high_to_value("Invalid")

666

except ValueError as e:

667

print(f"Invalid scale error: {e}")

668

669

try:

670

invalid_confidence = value_to_none_low_medium_high(150)

671

except ValueError as e:

672

print(f"Invalid confidence error: {e}")

673

```

674

675

### Error Handling Utilities

676

677

Utilities for handling and validating STIX objects with error checking.

678

679

```python

680

from stix2.exceptions import STIXError

681

682

def safe_type_check(obj, check_func, default=False):

683

"""Safely perform type check with error handling."""

684

try:

685

return check_func(obj)

686

except (STIXError, AttributeError, TypeError) as e:

687

print(f"Type check error: {e}")

688

return default

689

690

def validate_stix_object(obj):

691

"""Validate STIX object structure and properties."""

692

validation_results = {

693

'valid': True,

694

'errors': [],

695

'warnings': []

696

}

697

698

# Check if it's a recognized STIX object

699

if not is_object(obj):

700

validation_results['valid'] = False

701

validation_results['errors'].append("Not a valid STIX object")

702

return validation_results

703

704

# Check required properties

705

if hasattr(obj, 'id'):

706

obj_type = get_type_from_id(obj.id)

707

if obj_type != getattr(obj, 'type', None):

708

validation_results['warnings'].append(

709

f"ID type '{obj_type}' doesn't match object type '{obj.type}'"

710

)

711

else:

712

validation_results['errors'].append("Missing required 'id' property")

713

validation_results['valid'] = False

714

715

# Check timestamps

716

if hasattr(obj, 'created') and hasattr(obj, 'modified'):

717

try:

718

created = parse_into_datetime(obj.created)

719

modified = parse_into_datetime(obj.modified)

720

if modified < created:

721

validation_results['warnings'].append(

722

"Modified timestamp is before created timestamp"

723

)

724

except ValueError as e:

725

validation_results['errors'].append(f"Invalid timestamp format: {e}")

726

727

# Type-specific validations

728

if is_sdo(obj):

729

validation_results['warnings'].append("SDO validation passed")

730

elif is_sco(obj):

731

validation_results['warnings'].append("SCO validation passed")

732

elif is_sro(obj):

733

# Check relationship references

734

if hasattr(obj, 'source_ref') and hasattr(obj, 'target_ref'):

735

source_type = get_type_from_id(obj.source_ref)

736

target_type = get_type_from_id(obj.target_ref)

737

if not source_type or not target_type:

738

validation_results['warnings'].append(

739

"Invalid source_ref or target_ref format"

740

)

741

742

return validation_results

743

744

# Test validation

745

validation_result = validate_stix_object(indicator)

746

print(f"Validation result: {validation_result}")

747

748

# Safe type checking

749

unknown_object = {"type": "unknown-type"}

750

is_sdo_safe = safe_type_check(unknown_object, is_sdo, default=False)

751

print(f"Unknown object is SDO: {is_sdo_safe}") # False

752

```