Create Your Own DSSE

JFrog Artifactory Documentation

Products
JFrog Artifactory
Content Type
User Guide
ft:sourceType
Paligo

Subscription Information

This feature is supported with the Enterprise+ license.

This section describes how to create your own DSSE envelope containing evidence that can be attached to an artifact in Artifactory without using the Create Evidence CLI. DSSE is a standard for signing arbitrary data, as described here.

Note

The example below is written in Go, but other languages can also be used.

The complete code can be found at: https://github.com/jfrog/jfrog-cli-artifactory/blob/main/evidence/create_base.go

  1. Load the JSON file (known as the predicate) containing the evidence. This is the inner layer of the evidence file.

    predicate, err := os.ReadFile(ec.predicateFilePath)
    if err != nil {
        return err
    }
  2. Next, build the payload, which is the middle layer of the evidence file. Create an in-toto statement containing the predicate, the predicate type, your server details, and the user.

    In addition, you must define the evidence subject, which will be the complete repository path to an artifact already found in Artifactory. You have the option of including the subject's SHA256, which is then validated against the subject in Artifactory.

    Important

    In addition to the standard components of an in-toto statement (type, predicateType, and predicate), you must also provide the following JFrog extensions:

    • createdAt

      (must follow the format: timeLayout = "2006-01-02T15:04:05.000Z")

    • createdBy

    intotoStatement := intoto.NewStatement(predicate, ec.predicateType, ec.serverDetails.User)
    err = intotoStatement.SetSubject(servicesManager, ec.subject)
    if err != nil {
        return err
    } (edi
  3. Turn the in-toto statement into a JSON file.

    intotoJson, err := intotoStatement.Marshal()
        if err != nil {
    	return err
        }
  4. Load your private key. This is the key that will be used to sign the evidence.

    keyFile, err := os.ReadFile(ec.key)
    if err != nil {
        return err
    }
  5. Identify the private key type. (supported types include: RSA, ECDSA, ED25519)

    privateKey, err := cryptox.ReadKey(keyFile)
    if err != nil {
        return err
    }
  6. [optional] Set the key ID. If this option is used, the key ID must match a keyId defined in Artifactory.

    privateKey.KeyID = ec.keyId
  7. Create a signer based on the private key.

    signers, err := createSigners(privateKey)
    if err != nil {
        return err
    }
  8. Use the signer to create an envelope signer.

    envelopeSigner, err := dsse.NewEnvelopeSigner(signers...)
    if err != nil {
        return err
    }
  9. Sign the DSSE envelope, which is the outer layer of the evidence file. This requires the payload type and the payload created earlier.

    signedEnvelope, err := envelopeSigner.SignPayload(intoto.PayloadType, intotoJson)
    if err != nil {
        return err
    }

    The signed evidence is now ready to be deployed to Artifactory (via the Evidence service).

  10. Encode the signed envelope into a byte slice in preparation for deployment (upload) to Artifactory.

    envelopeBytes, err := json.Marshal(signedEnvelope)
    if err != nil {
        return err
    }
    evidenceManager, err := utils.CreateEvidenceServiceManager(serverDetails, false)
    if err != nil {
        return err
    }
    evidenceDetails := evidenceService.EvidenceDetails{
        SubjectUri:  strings.Split(ec.subject, "@")[0],
        DSSEFileRaw: envelopeBytes,
    }
    _, err = evidenceManager.UploadEvidence(evidenceDetails)
    if err != nil {
        return err
    }