Code Signing

ownCloud supports code signing for the core releases and for ownCloud applications. Code signing gives users an additional layer of security by ensuring that nobody other than authorized individuals can push updates.

It also ensures that all upgrades have been executed properly, so that no files are left behind and all old files are properly replaced. In the past, invalid updates were a significant source of errors when updating ownCloud.

Starting with ownCloud 11, app code signing is mandatory. An unsigned or invalidly-signed third-party app is blocked — not merely flagged with a warning — when it is installed, updated, or enabled. See Legacy Signatures for the transition period that applies to apps signed under the previous scheme.

Overview

ownCloud uses an X.509 based approach to authenticate code. Signing and verification are handled by a public-key infrastructure (PKI) hosted in the owncloud/developer-certificates repository:

  • A three-tier certificate authority (the ownCloud Code Signing Root CA G2 and an intermediate CA) issues short-lived leaf certificates, each scoped to a single application identifier through the certificate’s CN attribute.

  • Each ownCloud release ships the root CA certificate so that the server can verify the whole chain offline.

  • A public issuance ledger records which repository owns which app identifier, and a published certificate revocation list (CRL) lets the server reject revoked certificates.

Signing produces a signature.json file (schema v2) inside the application’s appinfo/ folder. It contains:

hashes

A canonical manifest of every file in the folder with its SHA-512 hash.

certificate

The leaf certificate used for signing, together with the intermediate chain. Bundling the certificate means that even if a developer loses their key, future updates can still be verified once a new certificate is issued.

signature

A signature over the canonical manifest that can be verified using the bundled certificate.

The signing itself is done with the standalone ocsign command-line tool. Unlike the previous method, ocsign does not require a running or bootstrapped ownCloud instance — it is a self-contained binary. Signing no longer relies on a server-side occ command.

Get a Signing Certificate

Before you can sign an app you need a leaf certificate for its application identifier. The application identifier is the id declared in the app’s appinfo/info.xml and must match the grammar ^[a-z][a-z0-9_.-]{2,63}$ (it must start with a letter, may contain lowercase letters, digits, _, . and -, and be at least three characters long).

The following examples assume that you are signing an application named example-app.

Step 1: Generate a Private Key and CSR

Your private key never leaves your machine. An EC P-384 key is preferred; an RSA-4096 key is supported as a fallback (for example when a hardware security module or CI environment cannot generate EC keys). The CSR’s CN must equal your application identifier.

EC P-384 (preferred)
openssl ecparam -name secp384r1 -genkey -noout -out example-app.key
openssl req -new -key example-app.key -out example-app.csr -subj "/CN=example-app"
RSA-4096 (fallback)
openssl genrsa -out example-app.key 4096
openssl req -new -key example-app.key -out example-app.csr -subj "/CN=example-app"
Keep the private key file (example-app.key) secret and never disclose it to third parties.

Step 2: Request the Certificate

  1. Open a Request a code-signing certificate issue in the owncloud/developer-certificates repository using the provided issue form. Paste the contents of your CSR and enter your app’s source repository as owner/name.

  2. The enrollment bot replies with a one-time challenge value.

  3. Prove that you control the app repository by committing a file that contains exactly that value to the repository’s default branch at /.well-known/owncloud-codesigning-challenge.txt. You have 72 hours to do this.

  4. The bot verifies the challenge file and checks that the requested identifier matches the id in your appinfo/info.xml. If the identifier is unclaimed — or already owned by this repository — it issues the certificate and posts back the leaf certificate and the intermediate certificate.

  5. You may delete the challenge file afterwards.

Application identifiers are assigned on a first-come, first-served basis: an identifier is bound to the first repository that successfully claims it. This is recorded in the public issuance ledger and prevents identifier squatting.

Sign the App With ocsign

ocsign walks the application tree, builds the canonical file-hash manifest, signs it with your private key, and writes appinfo/signature.json.

Download a release binary from the ocsign releases page, or build it from source (Go is required):

go build ./cmd/ocsign

Sign the application by pointing ocsign at the app directory, your private key, the issued leaf certificate, and the intermediate chain:

ocsign --path ./example-app \
       --key example-app.key \
       --cert example-app-leaf.crt \
       --chain intermediate.crt

This writes example-app/appinfo/signature.json. Ship that file inside the app; servers verify it when the app is installed, updated, or enabled.

The most important flags are:

Flag Description

--path (required)

Path to the directory to sign. For an app, the directory whose appinfo/info.xml declares the app id.

--key (required)

Path to the signer’s PEM private key (EC P-384, or RSA-4096 / RSA-2048 fallback). Used locally only; never transmitted.

--cert (required)

Path to the issued leaf certificate (PEM). Its CN must equal the app identifier.

--chain

Path to a PEM file with the intermediate certificate(s) to embed in the signature.

--out

Override the output path (default: <path>/appinfo/signature.json).

--dry-run

Compute and print the manifest and the would-be signature.json to standard output without writing anything.

--version

Print the build version and exit.

ocsign returns the following exit codes: 0 success; 1 usage or input error (missing flag, unreadable key, certificate, or path); 2 signing error (key and certificate mismatch, unsupported key type); 3 attestation error (see Mode 2).

The signing algorithm follows the key type: an EC P-384 key produces an ecdsa-p384-sha384 signature, and an RSA key produces an rsa-pss-sha384 signature. Before signing, ocsign checks that the private key matches the certificate’s public key and that the certificate CN equals the app identifier.

Any change to the app after signing invalidates the signature, so remove any files you do not want to ship before signing, then re-sign. After signing, package the app and submit it to the ownCloud Marketplace — see Publishing in the ownCloud Marketplace.

Mode 2: Attestation (Planned)

The scheme defines a second, optional mode that attaches an ownCloud attestation (a trusted timestamp) to the signature. Mode 2 lets a release keep verifying after its signing certificate has expired, and lets revocations apply precisely by time. It is requested with the --attest flag:

ocsign --path ./example-app --key example-app.key \
       --cert example-app-leaf.crt --chain intermediate.crt \
       --attest --attest-repo owncloud/developer-certificates
Mode 2 attestation is not yet available. ocsign exits with a clear error if --attest is requested. Every app currently uses Mode 1 (the signature is valid while the certificate is valid, typically two years; re-sign on renewal).

Renew or Add a Certificate

Leaf certificates are valid for two years. To renew, or to obtain an additional certificate for the same app (for example a separate CI key and release key), open another certificate request for the same identifier from the same repository. The bot re-verifies repository control and appends a fresh certificate to the ledger entry. Multiple concurrently valid certificates are allowed.

Revoke a Certificate

If you still hold the private key, revoke a certificate yourself by opening a Request revocation issue in owncloud/developer-certificates and pasting a CMS revocation request:

printf 'revoke' | openssl cms -sign \
  -signer example-app-leaf.crt -inkey example-app.key \
  -outform PEM -nodetach -out revocation-request.pem

The bot verifies the CMS signature, matches the embedded certificate against the ledger, and revokes it automatically.

If you have lost the key, or you need to report a problematic app you do not own, do not use the issue form. Instead, file a report through the GitHub Security Advisory (VDP); the security team verifies the request and revokes the certificate.

Legacy Signatures

Apps signed under the previous (pre-2026) scheme — using the old server-side signing command and a certificate obtained through owncloud/appstore-issues — are accepted with a warning until 2026-12-31. After that date, only signatures produced under the new PKI are trusted.

Re-sign your apps with ocsign under the new PKI before 2026-12-31.

Verification and Errors

Administrators verify installed code with the occ integrity:check-core and occ integrity:check-app commands. The following errors can be encountered when verifying a code signature. For information about how to view these results, refer to the Issues section of the ownCloud Administration Manual.

INVALID_HASH

The file has a different hash than specified within signature.json. This usually happens when the file has been modified after writing the signature data.

FILE_MISSING

The file cannot be found but has been specified within signature.json. Either a required file has been left out, or signature.json needs to be regenerated.

EXTRA_FILE

The file does not exist in signature.json. This usually happens when a file has been added and signature.json has not been updated.

EXCEPTION

Another exception has prevented code verification. The following exceptions can occur:

Signature data not found.

The app has mandatory code signing enforced but no signature.json file was found in its appinfo folder.

Certificate is not valid.

The certificate was not issued by the official ownCloud code-signing PKI.

Certificate is not valid for required scope. (Requested: %s, current: %s)

The certificate is not valid for the app being checked. Certificates are only valid for the app identifier they were issued for.

Signature could not get verified.

There was a problem verifying the signature of signature.json.

Certificate has been revoked.

The certificate used to sign the application was revoked.

The full developer guide for the code-signing PKI is maintained alongside the PKI itself in the owncloud/developer-certificates repository (docs/developer-guide.md).