Skip to content

Commit

Permalink
chore: refactor codesign testing (#1010)
Browse files Browse the repository at this point in the history
* chore: test Travis/macOS with xcode10.1
* chore: copy codesign setup from electron/electron
* chore: only run codesign test on macOS hosts
  • Loading branch information
malept committed Jun 20, 2019
1 parent 8356c07 commit 2f6e385
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 69 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -3,7 +3,7 @@ os:
- osx
- windows
dist: xenial
osx_image: xcode8
osx_image: xcode10.1
language: node_js
node_js:
- '8'
Expand Down
2 changes: 0 additions & 2 deletions src/mac.js
Expand Up @@ -295,8 +295,6 @@ class MacApp extends App {
// Although not signed successfully, the application is packed.
common.warning(`Code sign failed; please retry manually. ${err}`)
}
} else {
return Promise.resolve()
}
}

Expand Down
16 changes: 1 addition & 15 deletions test/ci/before_install.sh
Expand Up @@ -8,21 +8,7 @@ case "$TRAVIS_OS_NAME" in
sudo apt-get install -y wine1.6
;;
"osx")
# Create CA
openssl req -newkey rsa:4096 -days 1 -x509 -nodes -subj \
"/C=CI/ST=Travis/L=Developer/O=Developer/CN=Developer CA" \
-out /tmp/root.cer -keyout /tmp/root.key
touch /tmp/certindex
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain \
/tmp/root.cer
# Create dev certificate
openssl req -newkey rsa:1024 -nodes -subj \
"/C=CI/ST=Travis/L=Developer/O=Developer/CN=Developer CodeCert" \
-out codesign.csr -keyout codesign.key
openssl ca -batch -config $(pwd)/test/ci/dev_ca.cnf -notext -create_serial \
-in codesign.csr -out codesign.cer
openssl pkcs12 -export -in codesign.cer -inkey codesign.key -out codesign.p12 -password pass:12345
security import codesign.p12 -k ~/Library/Keychains/login.keychain -P 12345 -T /usr/bin/codesign
"$(dirname $0)"/codesign/import-testing-cert-ci.sh
npm install wine-darwin@1.9.17-1
# Setup ~/.wine by running a command
./node_modules/.bin/wine hostname
Expand Down
16 changes: 16 additions & 0 deletions test/ci/codesign/codesign.cnf
@@ -0,0 +1,16 @@
[req]
distinguished_name = req_distinguished_name
prompt = no

[req_distinguished_name]
C = CA
ST = BC
L = Vancouver
O = ElectronJS
OU = BuildAutomation
CN = codesign.electronjs.org

[extended]
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,codeSigning

40 changes: 40 additions & 0 deletions test/ci/codesign/gen-trust.js
@@ -0,0 +1,40 @@
'use strict'

const cp = require('child_process')
const fs = require('fs')
const path = require('path')

const certificatePath = process.argv[2]
const outPath = process.argv[3]
const templatePath = path.resolve(__dirname, 'trust.xml')

const template = fs.readFileSync(templatePath, 'utf8')

const fingerprintResult = cp.spawnSync('openssl', ['x509', '-noout', '-fingerprint', '-sha1', '-inform', 'der', '-in', certificatePath])
if (fingerprintResult.status !== 0) {
console.error(fingerprintResult.stderr.toString())
process.exit(1)
}

const fingerprint = fingerprintResult.stdout.toString().replace(/^SHA1 Fingerprint=/, '').replace(/:/g, '').trim()

const serialResult = cp.spawnSync('openssl', ['x509', '-serial', '-noout', '-inform', 'der', '-in', certificatePath])
if (serialResult.status !== 0) {
console.error(serialResult.stderr.toString())
process.exit(1)
}

let serialHex = serialResult.stdout.toString().replace(/^serial=/, '').trim()
// Pad the serial number out to 18 hex chars
while (serialHex.length < 18) {
serialHex = `0${serialHex}`
}
const serialB64 = Buffer.from(serialHex, 'hex').toString('base64')

const trust = template
.replace(/{{FINGERPRINT}}/g, fingerprint)
.replace(/{{SERIAL_BASE64}}/g, serialB64)

fs.writeFileSync(outPath, trust)

console.log('Generated Trust Settings')
32 changes: 32 additions & 0 deletions test/ci/codesign/generate-identity.sh
@@ -0,0 +1,32 @@
#!/bin/sh

set -eo pipefail

dir="$(dirname $0)"/.working

cleanup() {
rm -rf "$dir"
}

trap cleanup EXIT

# Clean Up
cleanup

# Create Working Dir
mkdir -p "$dir"

# Generate Certs
openssl req -newkey rsa:2048 -nodes -keyout "$dir"/private.pem -x509 -days 1 -out "$dir"/certificate.pem -extensions extended -config "$(dirname $0)"/codesign.cnf
openssl x509 -inform PEM -in "$dir"/certificate.pem -outform DER -out "$dir"/certificate.cer
rm -f "$dir"/certificate.pem

# Import Certs
security import "$dir"/certificate.cer -k $KEY_CHAIN -T /usr/bin/codesign
security import "$dir"/private.pem -k $KEY_CHAIN -T /usr/bin/codesign

# Generate Trust Settings
node "$(dirname $0)"/gen-trust.js "$dir"/certificate.cer "$dir"/trust.xml

# Import Trust Settings
sudo security trust-settings-import -d "$dir/trust.xml"
20 changes: 20 additions & 0 deletions test/ci/codesign/import-testing-cert-ci.sh
@@ -0,0 +1,20 @@
#!/bin/sh

export KEY_CHAIN=mac-build.keychain
KEYCHAIN_PASSWORD=unsafe_keychain_pass
security create-keychain -p $KEYCHAIN_PASSWORD $KEY_CHAIN
# Make the keychain the default so identities are found
security default-keychain -s $KEY_CHAIN
# Unlock the keychain
security unlock-keychain -p $KEYCHAIN_PASSWORD $KEY_CHAIN
# Set keychain locking timeout to 3600 seconds
security set-keychain-settings -t 3600 -u $KEY_CHAIN

echo "Add keychain to keychain-list"
security list-keychains -s mac-build.keychain

echo Generating Identity
"$(dirname $0)"/generate-identity.sh

echo "Setting key partition list"
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD $KEY_CHAIN
138 changes: 138 additions & 0 deletions test/ci/codesign/trust.xml
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>trustList</key>
<dict>
<key>{{FINGERPRINT}}</key>
<dict>
<key>issuerName</key>
<data>
MH8xCzAJBgNVBAYTAkNBMQswCQYDVQQIDAJCQzESMBAGA1UEBwwJ
VmFuY291dmVyMRMwEQYDVQQKDApFbGVjdHJvbkpTMRgwFgYDVQQL
DA9CdWlsZEF1dG9tYXRpb24xIDAeBgNVBAMMF2NvZGVzaWduLmVs
ZWN0cm9uanMub3Jn
</data>
<key>modDate</key>
<date>2019-01-01T00:00:00Z</date>
<key>serialNumber</key>
<data>
{{SERIAL_BASE64}}
</data>
<key>trustSettings</key>
<array>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147409654</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAED
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>sslServer</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147408896</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAED
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>sslServer</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147409654</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAEI
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>SMIME</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147408872</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAEI
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>SMIME</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147409654</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAEJ
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>eapServer</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147409654</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAEL
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>ipsecServer</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147409654</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAEQ
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>CodeSigning</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147409654</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAEU
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>AppleTimeStamping</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
<dict>
<key>kSecTrustSettingsAllowedError</key>
<integer>-2147409654</integer>
<key>kSecTrustSettingsPolicy</key>
<data>
KoZIhvdjZAEC
</data>
<key>kSecTrustSettingsPolicyName</key>
<string>basicX509</string>
<key>kSecTrustSettingsResult</key>
<integer>1</integer>
</dict>
</array>
</dict>
</dict>
<key>trustVersion</key>
<integer>1</integer>
</dict>
</plist>
33 changes: 0 additions & 33 deletions test/ci/dev_ca.cnf

This file was deleted.

28 changes: 10 additions & 18 deletions test/darwin.js
Expand Up @@ -11,7 +11,7 @@ const { promisify } = require('util')
const test = require('ava')
const util = require('./_util')

childProcess.exec = promisify(childProcess.exec)
const exec = promisify(childProcess.exec)

const darwinOpts = {
name: 'darwinTest',
Expand Down Expand Up @@ -292,25 +292,17 @@ if (!(process.env.CI && process.platform === 'win32')) {
t.true(signOpts.hardenedRuntime, 'hardenedRuntime forced to true')
})

test.serial('end-to-end codesign', darwinTest(async (t, opts) => {
opts.osxSign = { identity: 'Developer CodeCert' }
if (process.platform === 'darwin') {
test.serial('end-to-end codesign', darwinTest(async (t, opts) => {
opts.osxSign = { identity: 'codesign.electronjs.org' }

const finalPath = (await packager(opts))[0]
const appPath = path.join(finalPath, opts.name + '.app')
await util.assertDirectory(t, appPath, 'The expected .app directory should exist')
try {
await childProcess.exec(`codesign -v ${appPath}`)
const finalPath = (await packager(opts))[0]
const appPath = path.join(finalPath, opts.name + '.app')
await util.assertDirectory(t, appPath, 'The expected .app directory should exist')
await exec(`codesign --verify --verbose ${appPath}`)
t.pass('codesign should verify successfully')
} catch (err) {
const notFound = err && err.code === 127

if (notFound) {
console.log('codesign not installed; skipped')
} else {
throw err
}
}
}))
}))
}

test.serial('macOS: binary naming', darwinTest(binaryNameTest))
test.serial('macOS: sanitized binary naming', darwinTest(binaryNameTest, { name: '@username/package-name' }, '@username-package-name'))
Expand Down

0 comments on commit 2f6e385

Please sign in to comment.