<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.mozilla.org/index.php?action=history&amp;feed=atom&amp;title=AMO%2FSigningService%2FAPI</id>
	<title>AMO/SigningService/API - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.mozilla.org/index.php?action=history&amp;feed=atom&amp;title=AMO%2FSigningService%2FAPI"/>
	<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=AMO/SigningService/API&amp;action=history"/>
	<updated>2026-08-02T14:56:53Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.10</generator>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=AMO/SigningService/API&amp;diff=1021179&amp;oldid=prev</id>
		<title>RyanTilder: Created page with &quot;== General Info ==  === Abstract === This document describes how addons are signed to be automatically in Mozilla&#039;s Marketplace infrastructure.  === Definitions === ; endpoint...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=AMO/SigningService/API&amp;diff=1021179&amp;oldid=prev"/>
		<updated>2014-10-01T20:48:40Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;== General Info ==  === Abstract === This document describes how addons are signed to be automatically in Mozilla&amp;#039;s Marketplace infrastructure.  === Definitions === ; endpoint...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;== General Info ==&lt;br /&gt;
&lt;br /&gt;
=== Abstract ===&lt;br /&gt;
This document describes how addons are signed to be automatically in Mozilla&amp;#039;s Marketplace infrastructure.&lt;br /&gt;
&lt;br /&gt;
=== Definitions ===&lt;br /&gt;
; endpoint-url : The full URI for the service including the &amp;lt;tt&amp;gt;version string&amp;lt;/tt&amp;gt; for the API as defined below.&lt;br /&gt;
; version string : This revision of the protocol is 1.0 so the version string is &amp;quot;/1.0/&amp;quot;.&lt;br /&gt;
; root certificate : The signing CA&amp;#039;s root certificate in standard X.509 format.  This certificate will be included in each build of the user agent.&lt;br /&gt;
; generated key and certificate : An very short lived private and public key pair that are generated in an automated fashion, on demand.  The public key is then certified by the CA root certificate.&lt;br /&gt;
; unsigned archive : A JAR file that has been uploaded by a developer but not signed by the service yet.&lt;br /&gt;
; signed archive : A JAR file that has been created by Zamboni to include the contents of the unsigned archive and the generated manifest and signature files.&lt;br /&gt;
; manifest file : A file describing the contents of a JAR file.  Format detailed [http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Manifest_Specification here].&lt;br /&gt;
; signature file : A file of the same format as the manifest file that contains a single entry for the manifest file. Official format detailed [http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Signature_File here].  Note that XPI signing is an &amp;#039;&amp;#039;&amp;#039;incompatible subset&amp;#039;&amp;#039;&amp;#039; of JAR signing due to changes made in how XPIs are verified for improved security.&lt;br /&gt;
; app id : A unique identifier for the combination of addon name and version that will be used in the generated key and certificate.  A strong preference for human readable.&lt;br /&gt;
&lt;br /&gt;
=== Related documentation ===&lt;br /&gt;
; JAR signing : [http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Signed_JAR_File JDK documentation]&lt;br /&gt;
; JAR validation : [http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Signature_Validation JDK documentation]&lt;br /&gt;
; PKCS#7 : [http://en.wikipedia.org/wiki/Cryptographic_Message_Syntax Cryptographic Message Syntax] is a brief intro with links&lt;br /&gt;
&lt;br /&gt;
=== Data formats ===&lt;br /&gt;
The data formats are described in depth in the [http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Signed_JAR_File JDK documentation].  There are three basic formats being dealt with:&lt;br /&gt;
* Zip archives&lt;br /&gt;
* An HTTP header like format for archive manifests and signatures&lt;br /&gt;
* PKCS#7 detached signature in DER format&lt;br /&gt;
&lt;br /&gt;
=== Components ===&lt;br /&gt;
; Signing clients : https://github.com/mozilla/signing-clients/&lt;br /&gt;
&lt;br /&gt;
signing-clients is just a simple library for generating, parsing, and formatting the manifest and signature file formats.&lt;br /&gt;
&lt;br /&gt;
; Trunion : https://github.com/mozilla/trunion/&lt;br /&gt;
&lt;br /&gt;
The actual signing service.  This is the same code base as the [[Apps/WebApplicationReceipt/SigningService|receipt signing service]] but runs in a separate process space to provide a degree of separation between app signing, receipt signing, and addon signing credentials.&lt;br /&gt;
&lt;br /&gt;
; Zamboni, packaged app handling specifically : https://github.com/mozilla/zamboni/blob/master/lib/crypto/packaged.py&lt;br /&gt;
&lt;br /&gt;
Zamboni is responsible for receiving and storing an uploaded application archive, generating manifest and signature files for it via the signing-clients library, requesting a signature from the trunion signing service, and creating a new signed application archive containing the additional three files.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
; POST http://&amp;lt;endpoint-url&amp;gt;/sign_addon OR http://&amp;lt;endpoint-url&amp;gt;/sign/addon : &lt;br /&gt;
&lt;br /&gt;
* This takes two arguments:&lt;br /&gt;
** the archive&amp;#039;s signature file as multipart/form-data as an input with the name &amp;quot;file&amp;quot; with a filename included. &lt;br /&gt;
** the app id for this XPI at this version.&lt;br /&gt;
* It then returns a PKCS#7 detached signature of the uploaded content in a JSON object with a single key and value pair.  The key is the uploaded content&amp;#039;s specified filename with its extension(&amp;quot;.sf&amp;quot;) replaced with &amp;quot;.rsa&amp;quot;.  The value is a base64 encoded representation of the PKCS#7 data.&lt;br /&gt;
&lt;br /&gt;
=== Example request ===&lt;br /&gt;
 POST /1.0/sign_addon HTTP/1.1&lt;br /&gt;
 Host: localhost:5000&lt;br /&gt;
 Content-Length: 306&lt;br /&gt;
 Content-Type: multipart/form-data; boundary=df8e3fdaf425408e956aff8ca19d0263&lt;br /&gt;
 Accept-Encoding: gzip, deflate, compress&lt;br /&gt;
 Accept: */*&lt;br /&gt;
 User-Agent: python-requests/0.14.2 CPython/2.7.1 Darwin/11.4.2&lt;br /&gt;
 &lt;br /&gt;
 --df8e3fdaf425408e956aff8ca19d0263&lt;br /&gt;
 Content-Disposition: form-data; name=&amp;quot;id&amp;quot;&lt;br /&gt;
 Content-Type: text/plain&lt;br /&gt;
&lt;br /&gt;
 digital-doughnuts-addon-v1.0&lt;br /&gt;
 --df8e3fdaf425408e956aff8ca19d0263&lt;br /&gt;
 Content-Disposition: form-data; name=&amp;quot;file&amp;quot;; filename=&amp;quot;zigbert.sf&amp;quot;&lt;br /&gt;
 Content-Type: application/octet-stream&lt;br /&gt;
 &lt;br /&gt;
 Signature-Version: 1.0&lt;br /&gt;
 MD5-Digest-Manifest: PTUbaADVign9DDK3ntq9ww==&lt;br /&gt;
 SHA1-Digest-Manifest: FkVPRYqW9UT8kcbm8VS08TIWsH4=&lt;br /&gt;
 &lt;br /&gt;
 --df8e3fdaf425408e956aff8ca19d0263--&lt;br /&gt;
&lt;br /&gt;
=== Example response ===&lt;br /&gt;
Response body truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
 HTTP/1.0 200 OK&lt;br /&gt;
 Server: PasteWSGIServer/0.5 Python/2.6.8&lt;br /&gt;
 Date: Wed, 01 Oct 2014 20:43:05 GMT&lt;br /&gt;
 Content-Type: application/json; charset=UTF-8&lt;br /&gt;
 Content-Length: 3607&lt;br /&gt;
 &lt;br /&gt;
 {&amp;quot;zigbert.rsa&amp;quot;: &amp;quot;MIIKfQYJKoZIhvcNAQcCoIIKbjCCCmoCAQExCzAJBgUrDgMCGgUAMAsGCSq...==&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
== HTTP response codes ==&lt;br /&gt;
; 200 OK : The request was processed successfully and the server is returning a PKCS#7 signature&lt;br /&gt;
; 400 Bad request : The request body was incorrectly formatted&lt;br /&gt;
; 401 Unauthorized : The authentication credentials are invalid.  At the moment authorization consists of a simple whitelist of IPs.  In the future this may be used to indicate a BrowserID or other authentication mechanism has failed or the credentials are not authorized to use the service.&lt;br /&gt;
; 409 Conflict : A certificate has already been generated for the app id provided&lt;br /&gt;
; 503 Service Unavailable : Indicates that the server(s) are undergoing maintenance.&lt;/div&gt;</summary>
		<author><name>RyanTilder</name></author>
	</entry>
</feed>