Repository: CycloneDX/cyclonedx-core-java
Pull request #378 (2024-03-14 19:33:05)

Support for Attestation in 1.6
It implements https://github.com/CycloneDX/specification/pull/348 


Patch:
diff --git a/src/main/java/org/cyclonedx/generators/AbstractBomGenerator.java b/src/main/java/org/cyclonedx/generators/AbstractBomGenerator.java
index 6b672111e..e50316679 100644
--- a/src/main/java/org/cyclonedx/generators/AbstractBomGenerator.java
+++ b/src/main/java/org/cyclonedx/generators/AbstractBomGenerator.java
@@ -11,6 +11,7 @@ import org.cyclonedx.util.serializer.LicenseChoiceSerializer;
 import org.cyclonedx.util.serializer.LifecycleSerializer;
 import org.cyclonedx.util.serializer.MetadataSerializer;
 import org.cyclonedx.util.serializer.OutputTypeSerializer;
+import org.cyclonedx.util.serializer.SignatorySerializer;
 
 public abstract class AbstractBomGenerator extends CycloneDxSchema
 {
@@ -58,5 +59,9 @@ public abstract class AbstractBomGenerator extends CycloneDxSchema
     SimpleModule evidenceModule = new SimpleModule();
     evidenceModule.addSerializer(new EvidenceSerializer(isXml, getSchemaVersion()));
     mapper.registerModule(evidenceModule);
+
+    SimpleModule signatoryModule = new SimpleModule();
+    signatoryModule.addSerializer(new SignatorySerializer(isXml));
+    mapper.registerModule(signatoryModule);
   }
 }
diff --git a/src/main/java/org/cyclonedx/model/Bom.java b/src/main/java/org/cyclonedx/model/Bom.java
index cb170bc48..749a61e34 100644
--- a/src/main/java/org/cyclonedx/model/Bom.java
+++ b/src/main/java/org/cyclonedx/model/Bom.java
@@ -30,6 +30,8 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
 import org.cyclonedx.Version;
+import org.cyclonedx.model.attestation.Declarations;
+import org.cyclonedx.model.definition.Definition;
 import org.cyclonedx.model.formulation.Formula;
 import org.cyclonedx.model.vulnerability.Vulnerability;
 import org.cyclonedx.util.deserializer.DependencyDeserializer;
@@ -55,6 +57,8 @@ import org.cyclonedx.util.deserializer.VulnerabilityDeserializer;
         "vulnerabilities",
         "annotations",
         "formulation",
+        "declarations",
+        "definitions",
         "signature"
 })
 public class Bom extends ExtensibleElement {
@@ -84,6 +88,12 @@ public class Bom extends ExtensibleElement {
     @VersionFilter(Version.VERSION_15)
     private List<Formula> formulation;
 
+    @VersionFilter(Version.VERSION_16)
+    private Definition definitions;
+
+    @VersionFilter(Version.VERSION_16)
+    private Declarations declarations;
+
     @VersionFilter(Version.VERSION_14)
     @JsonDeserialize(using = VulnerabilityDeserializer.class)
     private List<Vulnerability> vulnerabilities;
@@ -237,6 +247,22 @@ public class Bom extends ExtensibleElement {
         this.properties.add(property);
     }
 
+    public Declarations getDeclarations() {
+        return declarations;
+    }
+
+    public void setDeclarations(final Declarations declarations) {
+        this.declarations = declarations;
+    }
+
+    public Definition getDefinitions() {
+        return definitions;
+    }
+
+    public void setDefinitions(final Definition definitions) {
+        this.definitions = definitions;
+    }
+
     public int getVersion() {
         return version;
     }
diff --git a/src/main/java/org/cyclonedx/model/ExternalReference.java b/src/main/java/org/cyclonedx/model/ExternalReference.java
index 31c32a13b..a3c618629 100644
--- a/src/main/java/org/cyclonedx/model/ExternalReference.java
+++ b/src/main/java/org/cyclonedx/model/ExternalReference.java
@@ -117,6 +117,12 @@ public class ExternalReference {
         FORMULATION("formulation"),
         @JsonProperty("rfc-9116")
         RFC_9116("rfc-9116"),
+        @VersionFilter(Version.VERSION_16)
+        @JsonProperty("electronic-signature")
+        ELECTRONIC_SIGNATURE("electronic-signature"),
+        @VersionFilter(Version.VERSION_16)
+        @JsonProperty("digital-signature")
+        DIGITAL_SIGNATURE("digital-signature"),
         @JsonProperty("other")
         OTHER("other");
 
diff --git a/src/main/java/org/cyclonedx/model/Service.java b/src/main/java/org/cyclonedx/model/Service.java
index b692f996d..532dad38a 100644
--- a/src/main/java/org/cyclonedx/model/Service.java
+++ b/src/main/java/org/cyclonedx/model/Service.java
@@ -75,7 +75,7 @@ public class Service extends ExtensibleElement {
     private List<ExternalReference> externalReferences;
     @VersionFilter(Version.VERSION_13)
     private List<Property> properties;
-    @VersionFilter(value = Version.VERSION_16)
+    @VersionFilter(Version.VERSION_16)
     @JsonUnwrapped
     private Tags tags;
     private List<Service> services;
diff --git a/src/main/java/org/cyclonedx/model/definition/Definition.java b/src/main/java/org/cyclonedx/model/definition/Definition.java
new file mode 100644
index 000000000..d38edb3bf
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/definition/Definition.java
@@ -0,0 +1,30 @@
+package org.cyclonedx.model.definition;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "standards"
+})
+public class Definition
+{
+  private List<Standard> standards;
+
+  @JacksonXmlElementWrapper(localName = "standards")
+  @JacksonXmlProperty(localName = "standard")
+  public List<Standard> getStandards() {
+    return standards;
+  }
+
+  public void setStandards(final List<Standard> standards) {
+    this.standards = standards;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/definition/Level.java b/src/main/java/org/cyclonedx/model/definition/Level.java
new file mode 100644
index 000000000..75eb10988
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/definition/Level.java
@@ -0,0 +1,76 @@
+package org.cyclonedx.model.definition;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "identifier",
+    "title",
+    "text",
+    "description",
+    "requirements"
+})
+public class Level
+{
+  @JacksonXmlProperty(isAttribute = true, localName = "bom-ref")
+  @JsonProperty("bom-ref")
+  private String bomRef;
+
+  private String identifier;
+
+  private String title;
+
+  private String description;
+
+  private List<String> requirements;
+
+  public String getBomRef() {
+    return bomRef;
+  }
+
+  public void setBomRef(final String bomRef) {
+    this.bomRef = bomRef;
+  }
+
+  public String getIdentifier() {
+    return identifier;
+  }
+
+  public void setIdentifier(final String identifier) {
+    this.identifier = identifier;
+  }
+
+  public String getTitle() {
+    return title;
+  }
+
+  public void setTitle(final String title) {
+    this.title = title;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(final String description) {
+    this.description = description;
+  }
+
+  @JacksonXmlElementWrapper(localName = "requirements")
+  @JacksonXmlProperty(localName = "requirement")
+  public List<String> getRequirements() {
+    return requirements;
+  }
+
+  public void setRequirements(final List<String> requirements) {
+    this.requirements = requirements;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/definition/Requirement.java b/src/main/java/org/cyclonedx/model/definition/Requirement.java
new file mode 100644
index 000000000..2b70b27e4
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/definition/Requirement.java
@@ -0,0 +1,128 @@
+package org.cyclonedx.model.definition;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.Property;
+import org.cyclonedx.util.deserializer.StringListDeserializer;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "identifier",
+    "title",
+    "text",
+    "descriptions",
+    "openCre",
+    "parent",
+    "properties",
+    "externalReferences"
+})
+public class Requirement
+{
+  @JacksonXmlProperty(isAttribute = true, localName = "bom-ref")
+  @JsonProperty("bom-ref")
+  private String bomRef;
+  private String identifier;
+
+  private String title;
+
+  private String text;
+
+  private List<String> descriptions;
+
+  private List<String> openCre;
+
+  private String parent;
+
+  private List<Property> properties;
+
+  private List<ExternalReference> externalReferences;
+
+  public String getBomRef() {
+    return bomRef;
+  }
+
+  public void setBomRef(final String bomRef) {
+    this.bomRef = bomRef;
+  }
+
+  public String getIdentifier() {
+    return identifier;
+  }
+
+  public void setIdentifier(final String identifier) {
+    this.identifier = identifier;
+  }
+
+  public String getTitle() {
+    return title;
+  }
+
+  public void setTitle(final String title) {
+    this.title = title;
+  }
+
+  public String getText() {
+    return text;
+  }
+
+  public void setText(final String text) {
+    this.text = text;
+  }
+
+  @JacksonXmlElementWrapper(localName = "descriptions")
+  @JacksonXmlProperty(localName = "description")
+  public List<String> getDescriptions() {
+    return descriptions;
+  }
+
+  public void setDescriptions(final List<String> descriptions) {
+    this.descriptions = descriptions;
+  }
+
+  @JacksonXmlElementWrapper(useWrapping = false)
+  @JacksonXmlProperty(localName = "openCre")
+  public List<String> getOpenCre() {
+    return openCre;
+  }
+
+  public void setOpenCre(final List<String> openCre) {
+    this.openCre = openCre;
+  }
+
+  public String getParent() {
+    return parent;
+  }
+
+  public void setParent(final String parent) {
+    this.parent = parent;
+  }
+
+  @JacksonXmlElementWrapper(localName = "properties")
+  @JacksonXmlProperty(localName = "property")
+  public List<Property> getProperties() {
+    return properties;
+  }
+
+  public void setProperties(final List<Property> properties) {
+    this.properties = properties;
+  }
+
+  @JacksonXmlElementWrapper(localName = "externalReferences")
+  @JacksonXmlProperty(localName = "externalReference")
+  public List<ExternalReference> getExternalReferences() {
+    return externalReferences;
+  }
+
+  public void setExternalReferences(final List<ExternalReference> externalReferences) {
+    this.externalReferences = externalReferences;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/definition/Standard.java b/src/main/java/org/cyclonedx/model/definition/Standard.java
new file mode 100644
index 000000000..83f15e20d
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/definition/Standard.java
@@ -0,0 +1,121 @@
+package org.cyclonedx.model.definition;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.Signature;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "name",
+    "version",
+    "description",
+    "owner",
+    "requirements",
+    "levels",
+    "externalReferences",
+    "signature"
+})
+public class Standard
+{
+  @JacksonXmlProperty(isAttribute = true, localName = "bom-ref")
+  @JsonProperty("bom-ref")
+  private String bomRef;
+
+  private String name;
+
+  private String version;
+
+  private String description;
+
+  private String owner;
+
+  private List<Requirement> requirements;
+
+  private List<Level> levels;
+
+  private List<ExternalReference> externalReferences;
+
+  private Signature signature;
+
+  public String getBomRef() {
+    return bomRef;
+  }
+
+  public void setBomRef(final String bomRef) {
+    this.bomRef = bomRef;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public String getVersion() {
+    return version;
+  }
+
+  public void setVersion(final String version) {
+    this.version = version;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(final String description) {
+    this.description = description;
+  }
+
+  public String getOwner() {
+    return owner;
+  }
+
+  public void setOwner(final String owner) {
+    this.owner = owner;
+  }
+
+  @JacksonXmlElementWrapper(localName = "requirements")
+  @JacksonXmlProperty(localName = "requirement")
+  public List<Requirement> getRequirements() {
+    return requirements;
+  }
+
+  public void setRequirements(final List<Requirement> requirements) {
+    this.requirements = requirements;
+  }
+
+  public List<Level> getLevels() {
+    return levels;
+  }
+
+  public void setLevels(final List<Level> levels) {
+    this.levels = levels;
+  }
+
+  public List<ExternalReference> getExternalReferences() {
+    return externalReferences;
+  }
+
+  public void setExternalReferences(final List<ExternalReference> externalReferences) {
+    this.externalReferences = externalReferences;
+  }
+
+  public Signature getSignature() {
+    return signature;
+  }
+
+  public void setSignature(final Signature signature) {
+    this.signature = signature;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/util/deserializer/SignatoryDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/SignatoryDeserializer.java
new file mode 100644
index 000000000..db31c4703
--- /dev/null
+++ b/src/main/java/org/cyclonedx/util/deserializer/SignatoryDeserializer.java
@@ -0,0 +1,73 @@
+/*
+ * This file is part of CycloneDX Core (Java).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) OWASP Foundation. All Rights Reserved.
+ */
+package org.cyclonedx.util.deserializer;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.OrganizationalEntity;
+import org.cyclonedx.model.Signature;
+import org.cyclonedx.model.attestation.affirmation.Signatory;
+
+public class SignatoryDeserializer
+    extends JsonDeserializer<Signatory>
+{
+  private final ObjectMapper mapper = new ObjectMapper();
+  @Override
+  public Signatory deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
+      throws IOException
+  {
+    JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+
+    Signatory signatory = new Signatory();
+
+    if (node.has("name")) {
+      signatory.setName(node.get("name").asText());
+    }
+
+    if (node.has("role")) {
+      signatory.setRole(node.get("role").asText());
+    }
+
+    JsonNode signatureNode = node.get("signature");
+    if (signatureNode != null) {
+      Signature signature = mapper.convertValue(node.get("signature"), Signature.class);
+      signatory.setSignature(signature);
+      return signatory;
+    }
+    else {
+      // Both Organization and external references are mandatory
+      JsonNode organizationNode = node.get("organization");
+      JsonNode externalReferenceNode = node.get("externalReference");
+
+      if (organizationNode != null && externalReferenceNode != null) {
+        OrganizationalEntity organization = mapper.convertValue(organizationNode, OrganizationalEntity.class);
+        ExternalReference externalReference = mapper.convertValue(externalReferenceNode, ExternalReference.class);
+        signatory.setExternalReferenceAndOrganization(externalReference, organization);
+        return signatory;
+      }
+    }
+    return null;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/util/deserializer/StringListDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/StringListDeserializer.java
index 73f9be63b..1ed48fb51 100644
--- a/src/main/java/org/cyclonedx/util/deserializer/StringListDeserializer.java
+++ b/src/main/java/org/cyclonedx/util/deserializer/StringListDeserializer.java
@@ -19,9 +19,6 @@ public class StringListDeserializer
     if (p.getCurrentName().equalsIgnoreCase("aliases")) {
       return deserializeList(node, "alias");
     }
-    else if (p.getCurrentName().equalsIgnoreCase("tags")) {
-      return deserializeList(node, "tag");
-    }
     else if (p.getCurrentName().equalsIgnoreCase("endpoints")) {
       return deserializeList(node, "endpoint");
     }
diff --git a/src/main/java/org/cyclonedx/util/serializer/EvidenceSerializer.java b/src/main/java/org/cyclonedx/util/serializer/EvidenceSerializer.java
index 34fe88e8a..0f8d16a8e 100644
--- a/src/main/java/org/cyclonedx/util/serializer/EvidenceSerializer.java
+++ b/src/main/java/org/cyclonedx/util/serializer/EvidenceSerializer.java
@@ -42,27 +42,28 @@ public class EvidenceSerializer
   private void serializeJson(final JsonGenerator gen, final Evidence evidence, SerializerProvider serializerProvider) throws IOException {
     gen.writeStartObject();
     if (CollectionUtils.isNotEmpty(evidence.getIdentities())) {
-        if(version.getVersion()>=Version.VERSION_16.getVersion()) {
-          gen.writeObjectField("identity", evidence.getIdentities());
-        } else {
-          gen.writeObjectField("identity", evidence.getIdentities().get(0));
-        }
+      if (version.getVersion() >= Version.VERSION_16.getVersion()) {
+        gen.writeObjectField("identity", evidence.getIdentities());
+      }
+      else {
+        gen.writeObjectField("identity", evidence.getIdentities().get(0));
+      }
     }
 
-    if(CollectionUtils.isNotEmpty(evidence.getOccurrences())) {
+    if (CollectionUtils.isNotEmpty(evidence.getOccurrences())) {
       gen.writeObjectField("occurrences", evidence.getOccurrences());
     }
 
-    if(evidence.getCallstack()!=null) {
+    if (evidence.getCallstack() != null) {
       gen.writeObjectField("callstack", evidence.getCallstack());
     }
 
-    if(evidence.getLicenseChoice() != null) {
+    if (evidence.getLicenseChoice() != null) {
       gen.writeFieldName("licenses");
       new LicenseChoiceSerializer().serialize(evidence.getLicenseChoice(), gen, serializerProvider);
     }
 
-    if(CollectionUtils.isNotEmpty(evidence.getCopyright())) {
+    if (CollectionUtils.isNotEmpty(evidence.getCopyright())) {
       gen.writeFieldName("copyright");
       gen.writeStartArray();
       for (Copyright item : evidence.getCopyright()) {
diff --git a/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java b/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java
new file mode 100644
index 000000000..544231d87
--- /dev/null
+++ b/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java
@@ -0,0 +1,66 @@
+package org.cyclonedx.util.serializer;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
+import org.apache.commons.lang3.StringUtils;
+import org.cyclonedx.model.attestation.affirmation.Signatory;
+
+public class SignatorySerializer
+    extends StdSerializer<Signatory>
+{
+  private final boolean isXml;
+
+  public SignatorySerializer(boolean isXml) {
+    this(null, isXml);
+  }
+
+  public SignatorySerializer(Class<Signatory> t, boolean isXml) {
+    super(t);
+    this.isXml = isXml;
+  }
+
+  @Override
+  public void serialize(Signatory value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
+      throws IOException {
+    if (isXml && jsonGenerator instanceof ToXmlGenerator) {
+      ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator;
+      serializeJson(xmlGenerator, value);
+    } else {
+      serializeJson(jsonGenerator, value);
+    }
+  }
+
+  private void serializeJson(final JsonGenerator gen, final Signatory signatory)
+      throws IOException
+  {
+    gen.writeStartObject();
+
+    if (StringUtils.isNotBlank(signatory.getName())) {
+      gen.writeStringField("name", signatory.getName());
+    }
+
+    if (StringUtils.isNotBlank(signatory.getRole())) {
+      gen.writeStringField("role", signatory.getRole());
+    }
+
+    if (signatory.getSignature() != null) {
+      gen.writeObjectField("signature", signatory.getSignature());
+    }
+    else {
+      if (signatory.getExternalReference() != null && signatory.getOrganization() != null) {
+        gen.writeObjectField("organization", signatory.getOrganization());
+        gen.writeObjectField("externalReference", signatory.getExternalReference());
+      }
+    }
+    gen.writeEndObject();
+  }
+
+  @Override
+  public Class<Signatory> handledType() {
+    return Signatory.class;
+  }
+}


Test patch:
diff --git a/src/main/java/org/cyclonedx/model/attestation/Assessor.java b/src/main/java/org/cyclonedx/model/attestation/Assessor.java
new file mode 100644
index 000000000..cb04bf16b
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/Assessor.java
@@ -0,0 +1,49 @@
+package org.cyclonedx.model.attestation;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.OrganizationalEntity;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "thirdParty",
+    "organization"
+})
+public class Assessor
+{
+  @JacksonXmlProperty(isAttribute = true, localName = "bom-ref")
+  @JsonProperty("bom-ref")
+  private String bomRef;
+
+  private Boolean thirdParty;
+
+  private OrganizationalEntity organization;
+
+  public String getBomRef() {
+    return bomRef;
+  }
+
+  public void setBomRef(final String bomRef) {
+    this.bomRef = bomRef;
+  }
+
+  public Boolean getThirdParty() {
+    return thirdParty;
+  }
+
+  public void setThirdParty(final Boolean thirdParty) {
+    this.thirdParty = thirdParty;
+  }
+
+  public OrganizationalEntity getOrganization() {
+    return organization;
+  }
+
+  public void setOrganization(final OrganizationalEntity organization) {
+    this.organization = organization;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/Attestation.java b/src/main/java/org/cyclonedx/model/attestation/Attestation.java
new file mode 100644
index 000000000..15e9c6e8e
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/Attestation.java
@@ -0,0 +1,63 @@
+package org.cyclonedx.model.attestation;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.Signature;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "summary",
+    "assessor",
+    "mapList",
+    "signature"
+})
+public class Attestation
+{
+  private String summary;
+
+  @JacksonXmlProperty(isAttribute = true, localName = "assessor")
+  @JsonProperty("assessor")
+  private String assessor;
+
+  private List<AttestationMap> mapList;
+
+  private Signature signature;
+
+  public String getSummary() {
+    return summary;
+  }
+
+  public void setSummary(final String summary) {
+    this.summary = summary;
+  }
+
+  public String getAssessor() {
+    return assessor;
+  }
+
+  public void setAssessor(final String assessor) {
+    this.assessor = assessor;
+  }
+
+  public List<AttestationMap> getMapList() {
+    return mapList;
+  }
+
+  public void setMapList(final List<AttestationMap> mapList) {
+    this.mapList = mapList;
+  }
+
+  public Signature getSignature() {
+    return signature;
+  }
+
+  public void setSignature(final Signature signature) {
+    this.signature = signature;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/AttestationMap.java b/src/main/java/org/cyclonedx/model/attestation/AttestationMap.java
new file mode 100644
index 000000000..35dfed715
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/AttestationMap.java
@@ -0,0 +1,80 @@
+package org.cyclonedx.model.attestation;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+
+@JacksonXmlRootElement(localName = "map")
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "requirement",
+    "claims",
+    "counterClaims",
+    "conformance",
+    "confidence"
+})
+public class AttestationMap
+{
+  @JacksonXmlProperty(isAttribute = true, localName = "requirement")
+  @JsonProperty("requirement")
+  private String requirement;
+
+  private List<String> claims;
+
+  private List<String> counterClaims;
+
+  private Conformance conformance;
+
+  private Confidence confidence;
+
+  public String getRequirement() {
+    return requirement;
+  }
+
+  public void setRequirement(final String requirement) {
+    this.requirement = requirement;
+  }
+
+  @JacksonXmlElementWrapper(localName = "claims")
+  @JacksonXmlProperty(localName = "claim")
+  public List<String> getClaims() {
+    return claims;
+  }
+
+  public void setClaims(final List<String> claims) {
+    this.claims = claims;
+  }
+
+  @JacksonXmlElementWrapper(localName = "counterClaims")
+  @JacksonXmlProperty(localName = "counterClaim")
+  public List<String> getCounterClaims() {
+    return counterClaims;
+  }
+
+  public void setCounterClaims(final List<String> counterClaims) {
+    this.counterClaims = counterClaims;
+  }
+
+  public Conformance getConformance() {
+    return conformance;
+  }
+
+  public void setConformance(final Conformance conformance) {
+    this.conformance = conformance;
+  }
+
+  public Confidence getConfidence() {
+    return confidence;
+  }
+
+  public void setConfidence(final Confidence confidence) {
+    this.confidence = confidence;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/Claim.java b/src/main/java/org/cyclonedx/model/attestation/Claim.java
new file mode 100644
index 000000000..8168b408f
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/Claim.java
@@ -0,0 +1,127 @@
+package org.cyclonedx.model.attestation;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.Signature;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "target",
+    "predicate",
+    "mitigationStrategies",
+    "reasoning",
+    "evidence",
+    "counterEvidence",
+    "externalReferences",
+    "signature"
+})
+public class Claim
+{
+  @JacksonXmlProperty(isAttribute = true, localName = "bom-ref")
+  @JsonProperty("bom-ref")
+  private String bomRef;
+
+  private String target;
+
+  private String predicate;
+
+  private List<String> mitigationStrategies;
+
+  private String reasoning;
+
+  private List<String> evidence;
+
+  private List<String> counterEvidence;
+
+  private List<ExternalReference> externalReferences;
+
+  private Signature signature;
+
+  public String getBomRef() {
+    return bomRef;
+  }
+
+  public void setBomRef(final String bomRef) {
+    this.bomRef = bomRef;
+  }
+
+  public String getTarget() {
+    return target;
+  }
+
+  public void setTarget(final String target) {
+    this.target = target;
+  }
+
+  public String getPredicate() {
+    return predicate;
+  }
+
+  public void setPredicate(final String predicate) {
+    this.predicate = predicate;
+  }
+
+  @JacksonXmlElementWrapper(localName = "mitigationStrategies")
+  @JacksonXmlProperty(localName = "mitigationStrategy")
+  public List<String> getMitigationStrategies() {
+    return mitigationStrategies;
+  }
+
+  public void setMitigationStrategies(final List<String> mitigationStrategies) {
+    this.mitigationStrategies = mitigationStrategies;
+  }
+
+  public String getReasoning() {
+    return reasoning;
+  }
+
+  public void setReasoning(final String reasoning) {
+    this.reasoning = reasoning;
+  }
+
+  @JacksonXmlElementWrapper(localName = "evidences")
+  @JacksonXmlProperty(localName = "evidence")
+  public List<String> getEvidence() {
+    return evidence;
+  }
+
+  public void setEvidence(final List<String> evidence) {
+    this.evidence = evidence;
+  }
+
+  @JacksonXmlElementWrapper(localName = "counterEvidences")
+  @JacksonXmlProperty(localName = "counterEvidence")
+  public List<String> getCounterEvidence() {
+    return counterEvidence;
+  }
+
+  public void setCounterEvidence(final List<String> counterEvidence) {
+    this.counterEvidence = counterEvidence;
+  }
+
+  @JacksonXmlElementWrapper(localName = "externalReferences")
+  @JacksonXmlProperty(localName = "externalReference")
+  public List<ExternalReference> getExternalReferences() {
+    return externalReferences;
+  }
+
+  public void setExternalReferences(final List<ExternalReference> externalReferences) {
+    this.externalReferences = externalReferences;
+  }
+
+  public Signature getSignature() {
+    return signature;
+  }
+
+  public void setSignature(final Signature signature) {
+    this.signature = signature;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/Confidence.java b/src/main/java/org/cyclonedx/model/attestation/Confidence.java
new file mode 100644
index 000000000..a888a963c
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/Confidence.java
@@ -0,0 +1,36 @@
+package org.cyclonedx.model.attestation;
+
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "score",
+    "rationale"
+})
+public class Confidence
+{
+  private Integer score;
+
+  private String rationale;
+
+
+  public Integer getScore() {
+    return score;
+  }
+
+  public void setScore(final Integer score) {
+    this.score = score;
+  }
+
+  public String getRationale() {
+    return rationale;
+  }
+
+  public void setRationale(final String rationale) {
+    this.rationale = rationale;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/Conformance.java b/src/main/java/org/cyclonedx/model/attestation/Conformance.java
new file mode 100644
index 000000000..cddf11c3b
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/Conformance.java
@@ -0,0 +1,50 @@
+package org.cyclonedx.model.attestation;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "score",
+    "rationale",
+    "mitigationStrategies"
+})
+public class Conformance
+{
+  private Integer score;
+
+  private String rationale;
+
+  private List<String> mitigationStrategies;
+
+  public Integer getScore() {
+    return score;
+  }
+
+  public void setScore(final Integer score) {
+    this.score = score;
+  }
+
+  public String getRationale() {
+    return rationale;
+  }
+
+  public void setRationale(final String rationale) {
+    this.rationale = rationale;
+  }
+  @JacksonXmlElementWrapper(localName = "mitigationStrategies")
+  @JacksonXmlProperty(localName = "mitigationStrategy")
+  public List<String> getMitigationStrategies() {
+    return mitigationStrategies;
+  }
+
+  public void setMitigationStrategies(final List<String> mitigationStrategies) {
+    this.mitigationStrategies = mitigationStrategies;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/Declarations.java b/src/main/java/org/cyclonedx/model/attestation/Declarations.java
new file mode 100644
index 000000000..6146d1cc9
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/Declarations.java
@@ -0,0 +1,102 @@
+package org.cyclonedx.model.attestation;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.Signature;
+import org.cyclonedx.model.attestation.affirmation.Affirmation;
+import org.cyclonedx.model.attestation.evidence.Evidence;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "assessors",
+    "attestations",
+    "claims",
+    "evidence",
+    "targets",
+    "affirmation",
+    "signature"
+})
+public class Declarations
+{
+  private List<Assessor> assessors;
+
+  private List<Attestation> attestations;
+
+  private List<Claim> claims;
+
+  private List<Evidence> evidence;
+
+  private Targets targets;
+
+  private Affirmation affirmation;
+
+  private Signature signature;
+
+  public List<Assessor> getAssessors() {
+    return assessors;
+  }
+
+  public void setAssessors(final List<Assessor> assessors) {
+    this.assessors = assessors;
+  }
+
+  @JacksonXmlElementWrapper(localName = "attestations")
+  @JacksonXmlProperty(localName = "attestation")
+  public List<Attestation> getAttestations() {
+    return attestations;
+  }
+
+  public void setAttestations(final List<Attestation> attestations) {
+    this.attestations = attestations;
+  }
+
+  @JacksonXmlElementWrapper(localName = "claims")
+  @JacksonXmlProperty(localName = "claim")
+  public List<Claim> getClaims() {
+    return claims;
+  }
+
+  public void setClaims(final List<Claim> claims) {
+    this.claims = claims;
+  }
+
+  @JacksonXmlElementWrapper(localName = "evidence")
+  @JacksonXmlProperty(localName = "evidence")
+  public List<Evidence> getEvidence() {
+    return evidence;
+  }
+
+  public void setEvidence(final List<Evidence> evidence) {
+    this.evidence = evidence;
+  }
+
+  public Targets getTargets() {
+    return targets;
+  }
+
+  public void setTargets(final Targets targets) {
+    this.targets = targets;
+  }
+
+  public Affirmation getAffirmation() {
+    return affirmation;
+  }
+
+  public void setAffirmation(final Affirmation affirmation) {
+    this.affirmation = affirmation;
+  }
+
+  public Signature getSignature() {
+    return signature;
+  }
+
+  public void setSignature(final Signature signature) {
+    this.signature = signature;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/Targets.java b/src/main/java/org/cyclonedx/model/attestation/Targets.java
new file mode 100644
index 000000000..7a3b53665
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/Targets.java
@@ -0,0 +1,58 @@
+package org.cyclonedx.model.attestation;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.Component;
+import org.cyclonedx.model.OrganizationalEntity;
+import org.cyclonedx.model.Service;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "organizations",
+    "components",
+    "services"
+})
+public class Targets
+{
+  private List<OrganizationalEntity> organizations;
+
+  private List<Component> components;
+
+  private List<Service> services;
+
+  @JacksonXmlElementWrapper(localName = "organizations")
+  @JacksonXmlProperty(localName = "organization")
+  public List<OrganizationalEntity> getOrganizations() {
+    return organizations;
+  }
+
+  public void setOrganizations(final List<OrganizationalEntity> organizations) {
+    this.organizations = organizations;
+  }
+
+  @JacksonXmlElementWrapper(localName = "components")
+  @JacksonXmlProperty(localName = "component")
+  public List<Component> getComponents() {
+    return components;
+  }
+
+  public void setComponents(final List<Component> components) {
+    this.components = components;
+  }
+
+  @JacksonXmlElementWrapper(localName = "services")
+  @JacksonXmlProperty(localName = "service")
+  public List<Service> getServices() {
+    return services;
+  }
+
+  public void setServices(final List<Service> services) {
+    this.services = services;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/affirmation/Affirmation.java b/src/main/java/org/cyclonedx/model/attestation/affirmation/Affirmation.java
new file mode 100644
index 000000000..dd4ddd998
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/affirmation/Affirmation.java
@@ -0,0 +1,52 @@
+package org.cyclonedx.model.attestation.affirmation;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.Signature;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "statement",
+    "signatories",
+    "signature"
+})
+public class Affirmation
+{
+  private String statement;
+
+  private List<Signatory> signatories;
+
+  private Signature signature;
+
+  public String getStatement() {
+    return statement;
+  }
+
+  public void setStatement(final String statement) {
+    this.statement = statement;
+  }
+
+  @JacksonXmlProperty(localName = "signatory")
+  @JacksonXmlElementWrapper(useWrapping = false)
+  public List<Signatory> getSignatories() {
+    return signatories;
+  }
+
+  public void setSignatories(final List<Signatory> signatories) {
+    this.signatories = signatories;
+  }
+
+  public Signature getSignature() {
+    return signature;
+  }
+
+  public void setSignature(final Signature signature) {
+    this.signature = signature;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/affirmation/Signatory.java b/src/main/java/org/cyclonedx/model/attestation/affirmation/Signatory.java
new file mode 100644
index 000000000..17e61dfd9
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/affirmation/Signatory.java
@@ -0,0 +1,86 @@
+package org.cyclonedx.model.attestation.affirmation;
+
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.OrganizationalEntity;
+import org.cyclonedx.model.Signature;
+import org.cyclonedx.util.deserializer.SignatoryDeserializer;
+
+@JsonTypeName("signatory")
+@JsonSubTypes({
+    @JsonSubTypes.Type(value = Signature.class, name = "signature"),
+    @JsonSubTypes.Type(value = OrganizationalEntity.class, name = "organization"),
+    @JsonSubTypes.Type(value = ExternalReference.class, name = "externalReference")
+})
+@JsonDeserialize(using = SignatoryDeserializer.class)
+public class Signatory
+{
+  private String name;
+
+  private String role;
+
+  private Signature signature;
+
+  private OrganizationalEntity organization;
+  private ExternalReference externalReference;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public String getRole() {
+    return role;
+  }
+
+  public void setRole(final String role) {
+    this.role = role;
+  }
+
+  public Signature getSignature() {
+    return signature;
+  }
+
+  public void setSignature(final Signature signature) {
+    this.signature = signature;
+
+    //If Signature is present organization and external reference are not allowed
+    organization = null;
+    externalReference = null;
+  }
+
+  public OrganizationalEntity getOrganization() {
+    return organization;
+  }
+
+  public void setOrganization(final OrganizationalEntity organization) {
+    this.organization = organization;
+    //if organization and external reference are present signature is not allowed
+    signature = null;
+  }
+
+  public ExternalReference getExternalReference() {
+    return externalReference;
+  }
+
+  public void setExternalReference(final ExternalReference externalReference) {
+    this.externalReference = externalReference;
+    //if organization and external reference are present signature is not allowed
+    signature = null;
+  }
+
+  public void setExternalReferenceAndOrganization(
+      final ExternalReference externalReference,
+      final OrganizationalEntity organization)
+  {
+    this.organization = organization;
+    this.externalReference = externalReference;
+    //if organization and external reference are present signature is not allowed
+    signature = null;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/evidence/Contents.java b/src/main/java/org/cyclonedx/model/attestation/evidence/Contents.java
new file mode 100644
index 000000000..9ad1310bb
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/evidence/Contents.java
@@ -0,0 +1,36 @@
+package org.cyclonedx.model.attestation.evidence;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import org.cyclonedx.model.AttachmentText;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "attachment",
+    "url",
+})
+public class Contents
+{
+  private AttachmentText attachment;
+
+  private String url;
+
+  public AttachmentText getAttachment() {
+    return attachment;
+  }
+
+  public void setAttachment(final AttachmentText attachment) {
+    this.attachment = attachment;
+  }
+
+  public String getUrl() {
+    return url;
+  }
+
+  public void setUrl(final String url) {
+    this.url = url;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/evidence/Data.java b/src/main/java/org/cyclonedx/model/attestation/evidence/Data.java
new file mode 100644
index 000000000..b9b29116f
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/evidence/Data.java
@@ -0,0 +1,77 @@
+package org.cyclonedx.model.attestation.evidence;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.component.modelCard.data.Governance;
+import org.cyclonedx.util.deserializer.StringListDeserializer;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "name",
+    "contents",
+    "classification",
+    "sensitiveData",
+    "governance"
+})
+public class Data
+{
+  private String name;
+
+  private Contents contents;
+
+  private String classification;
+
+  private List<String> sensitiveData;
+
+  private Governance governance;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+
+  public Contents getContents() {
+    return contents;
+  }
+
+  public void setContents(final Contents contents) {
+    this.contents = contents;
+  }
+
+ @JacksonXmlElementWrapper(useWrapping = false)
+ @JacksonXmlProperty(localName = "sensitiveData")
+  public List<String> getSensitiveData() {
+    return sensitiveData;
+  }
+
+  public void setSensitiveData(final List<String> sensitiveData) {
+    this.sensitiveData = sensitiveData;
+  }
+
+  public Governance getGovernance() {
+    return governance;
+  }
+
+  public void setGovernance(final Governance governance) {
+    this.governance = governance;
+  }
+
+  public String getClassification() {
+    return classification;
+  }
+
+  public void setClassification(final String classification) {
+    this.classification = classification;
+  }
+}
diff --git a/src/main/java/org/cyclonedx/model/attestation/evidence/Evidence.java b/src/main/java/org/cyclonedx/model/attestation/evidence/Evidence.java
new file mode 100644
index 000000000..9d21610a9
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/attestation/evidence/Evidence.java
@@ -0,0 +1,128 @@
+package org.cyclonedx.model.attestation.evidence;
+
+import java.util.Date;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.OrganizationalContact;
+import org.cyclonedx.model.Signature;
+import org.cyclonedx.util.serializer.CustomDateSerializer;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonPropertyOrder({
+    "type",
+    "description",
+    "data",
+    "created",
+    "expires",
+    "author",
+    "reviewer",
+    "signature"
+})
+public class Evidence
+{
+  @JacksonXmlProperty(isAttribute = true, localName = "bom-ref")
+  @JsonProperty("bom-ref")
+  private String bomRef;
+
+  private String type;
+
+  private String description;
+
+  private List<Data> data;
+
+  @JsonSerialize(using = CustomDateSerializer.class)
+  private Date created;
+
+  @JsonSerialize(using = CustomDateSerializer.class)
+  private Date expires;
+
+  private OrganizationalContact author;
+
+  private OrganizationalContact reviewer;
+
+  private Signature signature;
+
+  public String getBomRef() {
+    return bomRef;
+  }
+
+  public void setBomRef(final String bomRef) {
+    this.bomRef = bomRef;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(final String type) {
+    this.type = type;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(final String description) {
+    this.description = description;
+  }
+
+  @JacksonXmlElementWrapper(useWrapping = false)
+  @JacksonXmlProperty(localName = "data")
+  //@JsonDeserialize(using = DataDeserializer.class)
+  @JsonProperty("data")
+  public List<Data> getData() {
+    return data;
+  }
+
+  public void setData(final List<Data> data) {
+    this.data = data;
+  }
+
+  public Date getCreated() {
+    return created;
+  }
+
+  public void setCreated(final Date created) {
+    this.created = created;
+  }
+
+  public Date getExpires() {
+    return expires;
+  }
+
+  public void setExpires(final Date expires) {
+    this.expires = expires;
+  }
+
+  public OrganizationalContact getAuthor() {
+    return author;
+  }
+
+  public void setAuthor(final OrganizationalContact author) {
+    this.author = author;
+  }
+
+  public OrganizationalContact getReviewer() {
+    return reviewer;
+  }
+
+  public void setReviewer(final OrganizationalContact reviewer) {
+    this.reviewer = reviewer;
+  }
+
+  public Signature getSignature() {
+    return signature;
+  }
+
+  public void setSignature(final Signature signature) {
+    this.signature = signature;
+  }
+}