summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/unit/test_signed_manifest
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /security/manager/ssl/tests/unit/test_signed_manifest
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'security/manager/ssl/tests/unit/test_signed_manifest')
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/README.md17
-rwxr-xr-xsecurity/manager/ssl/tests/unit/test_signed_manifest/create_test_files.sh181
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/manifest.webapp10
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/nss_ctypes.py136
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/sign_b2g_manifest.py76
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/testInvalidSignedManifest/manifest.sigbin0 -> 1501 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/testValidSignedManifest/manifest.sigbin0 -> 1494 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/trusted_ca1.derbin0 -> 928 bytes
8 files changed, 420 insertions, 0 deletions
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/README.md b/security/manager/ssl/tests/unit/test_signed_manifest/README.md
new file mode 100644
index 000000000..a442c7052
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/README.md
@@ -0,0 +1,17 @@
+This folder contains the scripts needed to generate signed manifest files
+to verify the Trusted Hosted Apps concept.
+
+Prerequisites:
+
+* NSS 3.4 or higher.
+* Python 2.7 (should work with 2.6 also)
+* Bash
+* OpenSSL
+
+Usage:
+
+Run
+ I) For usage info execute ./create_test_files.sh --help
+
+ II) Upload the signed manifest.webapp and manifest.sig to the
+ application hosting server.
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/create_test_files.sh b/security/manager/ssl/tests/unit/test_signed_manifest/create_test_files.sh
new file mode 100755
index 000000000..cddbe17ec
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/create_test_files.sh
@@ -0,0 +1,181 @@
+#!/bin/bash
+#
+# Mode: shell-script; sh-indentation:2;
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+export BASE_PATH=`dirname $0`
+echo $BASE_PATH
+
+# location of the 'sign_b2g_manifest.py' script
+export SIGN_SCR_PATH=.
+
+DB_PATH=${BASE_PATH}/signingDB
+PASSWORD_FILE=${DB_PATH}/passwordfile
+VALID_MANIFEST_PATH=${BASE_PATH}/testValidSignedManifest
+INVALID_MANIFEST_PATH=${BASE_PATH}/testInvalidSignedManifest
+
+TRUSTED_EE=trusted_ee1
+UNTRUSTED_EE=untrusted_ee1
+TRUSTED_CA=trusted_ca1
+UNTRUSTED_CA=untrusted_ca1
+
+# Print usage info
+usage() {
+ echo
+ echo
+ tput bold
+ echo "NAME"
+ tput sgr0
+ echo " create_test_files.sh - Signing a manifest for Trusted Hosted Apps."
+ echo
+ tput bold
+ echo "SYNOPSIS"
+ tput sgr0
+ echo " create_test_files.sh"
+ echo " create_test_files.sh [--regenerate-test-certs]"
+ echo " create_test_files.sh [--help]"
+ echo
+ tput bold
+ echo "DESCRIPTION"
+ tput sgr0
+ echo " The script signs a manifest for Trusted Hosted Apps if no parameter"
+ echo " is given and if the manifest file and a certificate database directory"
+ echo " is present in the current directory."
+ echo " Two directories ./testValidSignedManifest and ./testInvalidSignedManifest"
+ echo " are generated containing a manifest signature file each, signed with valid"
+ echo " and invalid certificates respectively."
+ echo " If the --regenerate-test-certs parameter is given, a new certificate database"
+ echo " directory is generated before the signing takes place."
+ echo " If the certificate database is not present and the --regenerate-test-certs"
+ echo " parameter is not given the script exits whithout any operations."
+ echo
+ tput bold
+ echo "OPTIONS"
+ echo " --regenerate-test-certs,"
+ tput sgr0
+ echo " Generates a test certificate database and then signs the manifest.webapp"
+ echo " file in the current directory."
+ echo
+ tput bold
+ echo " --help,"
+ tput sgr0
+ echo " Show this usage information."
+ echo
+}
+
+# Function to create a signing database
+# Parameters:
+# $1: Output directory (where the DB will be created)
+# $2: Password file
+createDB() {
+ local db_path=${1}
+ local password_file=${2}
+
+ mkdir -p ${db_path}
+ echo insecurepassword > ${password_file}
+ certutil -d ${db_path} -N -f ${password_file} 2>&1 >/dev/null
+}
+
+# Add a CA cert and a signing cert to the database
+# Arguments:
+# $1: DB directory
+# $2: CA CN (don't include the CN=, just the value)
+# $3: Signing Cert CN (don't include the CN=, just the value)
+# $4: CA short name (don't use spaces!)
+# $5: Signing Cert short name (don't use spaces!)
+# $6: Password file
+addCerts() {
+ local db_path=${1}
+ local password_file=${6}
+
+ org="O=Example Trusted Corporation,L=Mountain View,ST=CA,C=US"
+ ca_subj="CN=${2},${org}"
+ ee_subj="CN=${3},${org}"
+
+ noisefile=/tmp/noise.$$
+ head -c 32 /dev/urandom > ${noisefile}
+
+ ca_responses=/tmp/caresponses.$$
+ ee_responses=/tmp/earesponses
+
+ echo y > ${ca_responses} # Is this a CA?
+ echo >> ${ca_responses} # Accept default path length constraint (no constraint)
+ echo y >> ${ca_responses} # Is this a critical constraint?
+ echo n > ${ee_responses} # Is this a CA?
+ echo >> ${ee_responses} # Accept default path length constraint (no constraint)
+ echo y >> ${ee_responses} # Is this a critical constraint?
+
+ make_cert="certutil -d ${db_path} -f ${password_file} -S -g 2048 -Z SHA256 \
+ -z ${noisefile} -y 3 -2 --extKeyUsage critical,codeSigning"
+ ${make_cert} -v 480 -n ${4} -m 1 -s "${ca_subj}" --keyUsage critical,certSigning \
+ -t ",,CTu" -x < ${ca_responses} 2>&1 >/dev/null
+ ${make_cert} -v 240 -n ${5} -c ${4} -m 2 -s "${ee_subj}" --keyUsage critical,digitalSignature \
+ -t ",,," < ${ee_responses} 2>&1 >/dev/null
+
+ certutil -d ${db_path} -L -n ${4} -r -o ${SIGN_SCR_PATH}/${4}.der
+
+ rm -f ${noisefile} ${ee_responses} ${ca_responses}
+}
+
+# Signs a manifest
+# Parameters:
+# $1: Database directory
+# $2: Unsigned manifest file path
+# $3: Signed manifest file path
+# $4: Nickname of the signing certificate
+# $5: Password file
+signManifest() {
+ local db_path=${1}
+ local password_file=${5}
+
+ python ${BASE_PATH}/${SIGN_SCR_PATH}/sign_b2g_manifest.py -d ${db_path} \
+ -f ${password_file} -k ${4} -i ${2} -o ${3}
+}
+
+# Generate the necessary files to be used for the signing
+generate_files() {
+ # First create a new couple of signing DBs
+ rm -rf ${DB_PATH} ${VALID_MANIFEST_PATH} ${INVALID_MANIFEST_PATH}
+ createDB ${DB_PATH} ${PASSWORD_FILE}
+ addCerts ${DB_PATH} "Trusted Valid CA" "Trusted Corp Cert" ${TRUSTED_CA} ${TRUSTED_EE} ${PASSWORD_FILE}
+ addCerts ${DB_PATH} "Trusted Invalid CA" "Trusted Invalid Cert" ${UNTRUSTED_CA} ${UNTRUSTED_EE} ${PASSWORD_FILE}
+}
+
+#Start of execution
+if [ ${1} ] && [ "${1}" == '--regenerate-test-certs' ]; then
+ generate_files
+elif [ "${1}" == '--help' ]; then
+ usage
+ exit 1
+else
+ if [ -d ${DB_PATH} ]; then
+ rm -rf ${VALID_MANIFEST_PATH} ${INVALID_MANIFEST_PATH}
+ else
+ echo "Error! The directory ${DB_PATH} does not exist!"
+ echo "New certificate database must be created!"
+ usage $0
+ exit 1
+ fi
+fi
+
+# Create all the test manifests
+mkdir -p ${VALID_MANIFEST_PATH}
+mkdir -p ${INVALID_MANIFEST_PATH}
+
+CURDIR=`pwd`
+cd $CURDIR
+
+# Sign a manifest file with a known issuer
+signManifest ${DB_PATH} ${BASE_PATH}/manifest.webapp \
+ ${VALID_MANIFEST_PATH}/manifest.sig \
+ ${TRUSTED_EE} ${PASSWORD_FILE}
+
+# Sign a manifest file with a unknown issuer
+signManifest ${DB_PATH} ${BASE_PATH}/manifest.webapp \
+ ${INVALID_MANIFEST_PATH}/manifest.sig \
+ ${UNTRUSTED_EE} ${PASSWORD_FILE}
+
+echo "Done!"
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/manifest.webapp b/security/manager/ssl/tests/unit/test_signed_manifest/manifest.webapp
new file mode 100644
index 000000000..ad477719b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/manifest.webapp
@@ -0,0 +1,10 @@
+{ "name": "Trusted App Example",
+ "description": "A Manifest for a Trusted Hosted Application",
+ "type": "trusted",
+ "launch_path": "/index.html",
+ "icons": { "128" : "icon-128.png" },
+ "version": 1,
+ "csp" : "script-src https://www.example.com; style-src https://www.example.com",
+ "permissions": { "device-storage:videos":{ "access": "readonly" }, "device-storage:pictures":{ "access": "readwrite" } },
+ "default_locale": "en-US"
+}
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/nss_ctypes.py b/security/manager/ssl/tests/unit/test_signed_manifest/nss_ctypes.py
new file mode 100644
index 000000000..a0c50b1ed
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/nss_ctypes.py
@@ -0,0 +1,136 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from ctypes import *
+import os
+import sys
+
+if sys.platform == 'darwin':
+ libprefix = "lib"
+ libsuffix = ".dylib"
+elif os.name == 'posix':
+ libprefix = "lib"
+ libsuffix = ".so"
+else: # assume windows
+ libprefix = ""
+ libsuffix = ".dll"
+
+plc = cdll.LoadLibrary(libprefix + "plc4" + libsuffix)
+nspr = cdll.LoadLibrary(libprefix + "nspr4" + libsuffix)
+nss = cdll.LoadLibrary(libprefix + "nss3" + libsuffix)
+smime = cdll.LoadLibrary(libprefix + "smime3" + libsuffix)
+
+nspr.PR_GetError.argtypes = []
+nspr.PR_GetError.restype = c_int32
+nspr.PR_ErrorToName.argtypes = [c_int32]
+nspr.PR_ErrorToName.restype = c_char_p
+
+def raise_if_not_SECSuccess(rv):
+ SECSuccess = 0
+ if (rv != SECSuccess):
+ raise ValueError(nspr.PR_ErrorToName(nspr.PR_GetError()))
+
+def raise_if_NULL(p):
+ if not p:
+ raise ValueError(nspr.PR_ErrorToName(nspr.PR_GetError()))
+ return p
+
+PRBool = c_int
+SECStatus = c_int
+
+# from secoidt.h
+SEC_OID_SHA1 = 4
+
+# from certt.h
+certUsageObjectSigner = 6
+
+class SECItem(Structure):
+ _fields_ = [("type", c_int),
+ ("data", c_char_p),
+ ("len", c_uint)]
+
+nss.NSS_Init.argtypes = [c_char_p]
+nss.NSS_Init.restype = SECStatus
+def NSS_Init(db_dir):
+ nss.NSS_Init.argtypes = [c_char_p]
+ nss.NSS_Init.restype = SECStatus
+ raise_if_not_SECSuccess(nss.NSS_Init(db_dir))
+
+nss.NSS_Shutdown.argtypes = []
+nss.NSS_Shutdown.restype = SECStatus
+def NSS_Shutdown():
+ raise_if_not_SECSuccess(nss.NSS_Shutdown())
+
+PK11PasswordFunc = CFUNCTYPE(c_char_p, c_void_p, PRBool, c_char_p)
+
+# pass the result of this as the wincx parameter when a wincx is required
+nss.PK11_SetPasswordFunc.argtypes = [PK11PasswordFunc]
+nss.PK11_SetPasswordFunc.restype = None
+
+# Set the return type as *void so Python doesn't touch it
+plc.PL_strdup.argtypes = [c_char_p]
+plc.PL_strdup.restype = c_void_p
+def SetPasswordContext(password):
+ def callback(slot, retry, arg):
+ return plc.PL_strdup(password)
+ wincx = PK11PasswordFunc(callback)
+ nss.PK11_SetPasswordFunc(wincx)
+ return wincx
+
+nss.CERT_GetDefaultCertDB.argtypes = []
+nss.CERT_GetDefaultCertDB.restype = c_void_p
+def CERT_GetDefaultCertDB():
+ return raise_if_NULL(nss.CERT_GetDefaultCertDB())
+
+nss.PK11_FindCertFromNickname.argtypes = [c_char_p, c_void_p]
+nss.PK11_FindCertFromNickname.restype = c_void_p
+def PK11_FindCertFromNickname(nickname, wincx):
+ return raise_if_NULL(nss.PK11_FindCertFromNickname(nickname, wincx))
+
+nss.CERT_DestroyCertificate.argtypes = [c_void_p]
+nss.CERT_DestroyCertificate.restype = None
+def CERT_DestroyCertificate(cert):
+ nss.CERT_DestroyCertificate(cert)
+
+smime.SEC_PKCS7CreateSignedData.argtypes = [c_void_p, c_int, c_void_p,
+ c_int, c_void_p,
+ c_void_p, c_void_p]
+smime.SEC_PKCS7CreateSignedData.restype = c_void_p
+def SEC_PKCS7CreateSignedData(cert, certusage, certdb, digestalg, digest, wincx):
+ item = SECItem(0, c_char_p(digest), len(digest))
+ return raise_if_NULL(smime.SEC_PKCS7CreateSignedData(cert, certusage, certdb,
+ digestalg,
+ pointer(item),
+ None, wincx))
+
+smime.SEC_PKCS7AddSigningTime.argtypes = [c_void_p]
+smime.SEC_PKCS7AddSigningTime.restype = SECStatus
+def SEC_PKCS7AddSigningTime(p7):
+ raise_if_not_SECSuccess(smime.SEC_PKCS7AddSigningTime(p7))
+
+smime.SEC_PKCS7IncludeCertChain.argtypes = [c_void_p, c_void_p]
+smime.SEC_PKCS7IncludeCertChain.restype = SECStatus
+def SEC_PKCS7IncludeCertChain(p7, wincx):
+ raise_if_not_SECSuccess(smime.SEC_PKCS7IncludeCertChain(p7, wincx))
+
+SEC_PKCS7EncoderOutputCallback = CFUNCTYPE(None, c_void_p, c_void_p, c_long)
+smime.SEC_PKCS7Encode.argtypes = [c_void_p, SEC_PKCS7EncoderOutputCallback,
+ c_void_p, c_void_p, c_void_p, c_void_p]
+smime.SEC_PKCS7Encode.restype = SECStatus
+def SEC_PKCS7Encode(p7, bulkkey, wincx):
+ outputChunks = []
+ def callback(chunks, data, len):
+ outputChunks.append(string_at(data, len))
+ callbackWrapper = SEC_PKCS7EncoderOutputCallback(callback)
+ raise_if_not_SECSuccess(smime.SEC_PKCS7Encode(p7, callbackWrapper,
+ None, None, None, wincx))
+ return "".join(outputChunks)
+
+smime.SEC_PKCS7DestroyContentInfo.argtypes = [c_void_p]
+smime.SEC_PKCS7DestroyContentInfo.restype = None
+def SEC_PKCS7DestroyContentInfo(p7):
+ smime.SEC_PKCS7DestroyContentInfo(p7)
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/sign_b2g_manifest.py b/security/manager/ssl/tests/unit/test_signed_manifest/sign_b2g_manifest.py
new file mode 100644
index 000000000..a7f060481
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/sign_b2g_manifest.py
@@ -0,0 +1,76 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import argparse
+from base64 import b64encode
+from hashlib import sha1
+import sys
+import ctypes
+import nss_ctypes
+
+def nss_create_detached_signature(cert, dataToSign, wincx):
+ certdb = nss_ctypes.CERT_GetDefaultCertDB()
+ p7 = nss_ctypes.SEC_PKCS7CreateSignedData(cert,
+ nss_ctypes.certUsageObjectSigner,
+ certdb,
+ nss_ctypes.SEC_OID_SHA1,
+ sha1(dataToSign).digest(),
+ wincx)
+ try:
+ nss_ctypes.SEC_PKCS7AddSigningTime(p7)
+ nss_ctypes.SEC_PKCS7IncludeCertChain(p7, wincx)
+ return nss_ctypes.SEC_PKCS7Encode(p7, None, wincx)
+ finally:
+ nss_ctypes.SEC_PKCS7DestroyContentInfo(p7)
+
+# Sign a manifest file
+def sign_file(in_file, out_file, cert, wincx):
+ contents = in_file.read()
+ in_file.close()
+
+ # generate base64 encoded string of the sha1 digest of the input file
+ in_file_hash = b64encode(sha1(contents).digest())
+
+ # sign the base64 encoded string with the given certificate
+ in_file_signature = nss_create_detached_signature(cert, in_file_hash, wincx)
+
+ # write the content of the output file
+ out_file.write(in_file_signature)
+ out_file.close()
+
+def main():
+ parser = argparse.ArgumentParser(description='Sign a B2G app manifest.')
+ parser.add_argument('-d', action='store',
+ required=True, help='NSS database directory')
+ parser.add_argument('-f', action='store',
+ type=argparse.FileType('rb'),
+ required=True, help='password file')
+ parser.add_argument('-k', action='store',
+ required=True, help="nickname of signing cert.")
+ parser.add_argument('-i', action='store', type=argparse.FileType('rb'),
+ required=True, help="input manifest file (unsigned)")
+ parser.add_argument('-o', action='store', type=argparse.FileType('wb'),
+ required=True, help="output manifest file (signed)")
+ args = parser.parse_args()
+
+ db_dir = args.d
+ password = args.f.readline().strip()
+ cert_nickname = args.k
+ cert = None
+
+ try:
+ nss_ctypes.NSS_Init(db_dir)
+ wincx = nss_ctypes.SetPasswordContext(password)
+ cert = nss_ctypes.PK11_FindCertFromNickname(cert_nickname, wincx)
+ sign_file(args.i, args.o, cert, wincx)
+ return 0
+ finally:
+ nss_ctypes.CERT_DestroyCertificate(cert)
+ nss_ctypes.NSS_Shutdown()
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/testInvalidSignedManifest/manifest.sig b/security/manager/ssl/tests/unit/test_signed_manifest/testInvalidSignedManifest/manifest.sig
new file mode 100644
index 000000000..d5eee196c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/testInvalidSignedManifest/manifest.sig
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/testValidSignedManifest/manifest.sig b/security/manager/ssl/tests/unit/test_signed_manifest/testValidSignedManifest/manifest.sig
new file mode 100644
index 000000000..996226351
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/testValidSignedManifest/manifest.sig
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/trusted_ca1.der b/security/manager/ssl/tests/unit/test_signed_manifest/trusted_ca1.der
new file mode 100644
index 000000000..bf05308cc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/trusted_ca1.der
Binary files differ