JSON Binding of the Incident Object Description Exchange Format
Extracted elements (25)
CBOR mapkeys (Table 4) are provided to minimize CBOR size by replacing long string keys with compact integer keys. The negative integer range is used for the most common top-level IODEF-Document attributes, while positive integers cover class-level elements.
JSON and CBOR alternatives to IODEF XML are defined because JSON is a well-used structured format suitable for machine processing, enabling automation of incident response operations. IODEF JSON provides all the expressivity of IODEF XML while giving implementers and operators an alternative exchange format.
Binaries in JSON IODEF are encoded as base64 (unlike XML IODEF which uses HEXBIN due to XML's inability to embed raw binaries). Signature, X509Data, and RawData use base64 encoding for JSON IODEF and binary representation for CBOR IODEF.
ENUM values defined in RFC 7970 are shared between XML IODEF and JSON/CBOR IODEF implementations. ENUM values are extensible and managed by IANA, with the same values used across all bindings.
Extension classes defined in RFC 7203 and referenced by RFC 7970 are represented by the STRUCTUREDINFO class in IODEF JSON, providing the bridge between the XML extension mechanism and JSON/CBOR.
In JSON IODEF, XML attributes and XML child elements of a class are both represented as JSON object attributes, and order of appearance is ignored. This differs from XML IODEF where element ordering and attribute syntax are distinct.
JSON's 'number' type only guarantees full integer precision for values between -2^53 and 2^53. When dealing with integers outside this range in IODEF JSON, precision loss must be considered by implementations.
MLStringType is modified to support a simple string type in addition to the predefined object type. Implementations must parse both forms. When converting between XML and JSON IODEF, information in ML_STRING must be preserved; when STRING is used instead of ML_STRING, parsers may assume 'xml:lang' is 'en'.
Several XML IODEF wrapper classes are deleted in JSON IODEF: Flow, ApplicationHeader, SignatureData, IndicatorData, ObservableReference, and Record. Their child elements are promoted directly into the parent class. This flattens the hierarchy without information loss.
The 'ipv6-net-mask' attribute of BulkObservable remains available for backward compatibility, but its use is not recommended because IPv6 does not use netmask.
When embedding raw data in STRUCTUREDINFO, base64 encoding defined in RFC 4648 Section 4 MUST be used for JSON IODEF, while binary representation MUST be used for CBOR IODEF.
IODEF abstract data types map to CBOR types: INTEGER to CBOR major types 0/1/tag 2/tag 3, REAL to float32, BYTE to tag 22 (eb64legacy), HEXBIN to tag 23 (eb16), DATETIME to tag 0 (tdate), URL to tag 32 (uri), and ML_STRING/SOFTWARE/STRUCTUREDINFO/EXTENSION to CBOR maps.
The EXTENSION type is implemented as an ExtensionType object with 'value', 'name', 'dtype', 'ext-dtype', 'meaning', 'formatid', 'restriction', 'ext-restriction', and 'observable-id' elements, providing a generic extension mechanism for information not otherwise representable in IODEF.
The Incident class contains mandatory 'purpose', 'IncidentID', 'GenerationTime', and 'Contact+' fields, with many optional fields including timing (DetectTime, StartTime, EndTime, RecoveryTime, ReportTime), Description, Assessment, Method, EventData, Indicator, and History.
The Indicator class (Section 3.29) contains a mandatory 'IndicatorID' and optional 'Observable', 'IndicatorExpression', 'AlternativeIndicatorID', 'BulkObservable', and related fields for expressing threat indicators and observables.
The IODEF abstract data types from RFC 7970 are mapped to native JSON types: INTEGER to JSON integer, REAL to JSON number, CHARACTER/STRING to JSON string, ML_STRING to a special object (Section 2.2.2), ENUM to ordered string values, DATETIME/TIMEZONE/PORTLIST to JSON string, and SOFTWARE/STRUCTUREDINFO/EXTENSION to JSON objects.
The IODEF-Document root class contains 'version', optional 'lang', 'format-id', 'private-enum-name', 'private-enum-id', one or more 'Incident' objects, and zero or more 'AdditionalData' objects.
The ML_STRING type is implemented as either a JSON object with 'value', 'lang', and 'translation-id' fields, or a plain text string. Implementations MUST be capable of parsing an MLStringType in both forms.
The normative IODEF JSON data model is specified in CDDL (Concise Data Definition Language per RFC 8610) in Section 6, with an additional JSON Schema provided in Appendix B. The CDDL specification is normative; the JSON Schema is informative.
The SOFTWARE type is implemented as a SoftwareType object with 'SoftwareReference', 'URL', and 'Description' elements. SoftwareReference itself contains 'value', 'spec-name' (e.g., 'cpe'), and 'dtype' fields for identifying specific software versions.
The STRUCTUREDINFO type is implemented as an object with 'SpecID', 'ext-SpecID', 'ContentID', 'RawData', and 'Reference' elements, used for embedding structured IDs or raw XML/binary data. Originally specified in RFC 7203 Section 4.4.
IANA considerations in Section 7 include registration of new media types for IODEF JSON ('application/iodef+json') and IODEF CBOR ('application/iodef+cbor'), and registration of CBOR mapkeys in a new IANA registry.
The security considerations of RFC 7970 apply to this JSON/CBOR binding. Implementers must consider risks inherent in JSON and CBOR parsing, including parser differentials, deeply nested structures, and integer overflow for values outside the ±2^53 range representable in JSON numbers.
A minimal valid IODEF JSON document requires 'version' (string '2.0'), 'lang', at least one 'Incident' containing 'purpose', 'IncidentID' (with 'id' and 'name'), 'GenerationTime', and at least one 'Contact'. The CBOR encoding of this minimal document uses CBOR map/array structures with the defined mapkeys.
CBOR mapkeys are defined as signed integers to minimize CBOR encoding size: top-level IODEF-Document fields use negative integers (e.g., 'iodef-version' = -24, 'iodef-Incident' = -19), while Incident and class-level fields use non-negative integers (e.g., 'iodef-IncidentID' = 2, 'iodef-Contact' = 14, 'iodef-Indicator' = 16).