mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 895601: Add tests to cert verification in psm. r=keeler.
This commit is contained in:
parent
dc9c3466c4
commit
6a58b9a90d
139
security/manager/ssl/tests/unit/psm_common_py/CertUtils.py
Normal file
139
security/manager/ssl/tests/unit/psm_common_py/CertUtils.py
Normal file
@ -0,0 +1,139 @@
|
||||
# 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/.
|
||||
|
||||
# This file requires openssl 1.0.0 at least
|
||||
|
||||
import os
|
||||
import random
|
||||
|
||||
def init_dsa(db_dir):
|
||||
"""
|
||||
Initialize dsa parameters
|
||||
|
||||
Sets up a set of params to be reused for DSA key generation
|
||||
|
||||
Arguments:
|
||||
db_dir -- location of the temporary params for the certificate
|
||||
"""
|
||||
dsa_key_params = db_dir + "/dsa_param.pem"
|
||||
os.system ("openssl dsaparam -out "+ dsa_key_params + " 2048")
|
||||
|
||||
|
||||
def generate_cert_generic(db_dir, dest_dir, serial_num, key_type, name,
|
||||
ext_text, signer_key_filename = "",
|
||||
signer_cert_filename = ""):
|
||||
"""
|
||||
Generate an x509 certificate with a sha256 signature
|
||||
|
||||
Preconditions:
|
||||
if dsa keys are to be generated init_dsa must have been called before.
|
||||
|
||||
|
||||
Arguments:
|
||||
db_dir -- location of the temporary params for the certificate
|
||||
dest_dir -- location of the x509 cert
|
||||
serial_num -- serial number for the cert (must be unique for each signer
|
||||
key)
|
||||
key_type -- the type of key generated: potential values: 'rsa', 'dsa',
|
||||
or any of the curves found by 'openssl ecparam -list_curves'
|
||||
name -- the common name for the cert, will match the prefix of the
|
||||
output cert
|
||||
ext_text -- the text for the x509 extensions to be added to the
|
||||
certificate
|
||||
signer_key_filename -- the filename of the key from which the cert will
|
||||
be signed if null the cert will be self signed (think CA
|
||||
roots).
|
||||
signer_cert_filename -- the certificate that will sign the certificate
|
||||
(used to extract signer info) it must be in DER format.
|
||||
|
||||
output:
|
||||
key_name -- the filename of the key file (PEM format)
|
||||
cert_name -- the filename of the output certificate (DER format)
|
||||
"""
|
||||
key_name = db_dir + "/"+ name + ".key"
|
||||
if key_type == 'rsa':
|
||||
os.system ("openssl genpkey -algorithm RSA -out " + key_name +
|
||||
" -pkeyopt rsa_keygen_bits:2048")
|
||||
elif key_type == 'dsa':
|
||||
dsa_key_params = db_dir + "/dsa_param.pem"
|
||||
os.system("openssl gendsa -out " + key_name + " " + dsa_key_params)
|
||||
else:
|
||||
#assume is ec
|
||||
os.system("openssl ecparam -out " + key_name + " -name "+ key_type +
|
||||
" -genkey");
|
||||
csr_name = db_dir + "/"+ name + ".csr"
|
||||
os.system ("openssl req -new -key " + key_name + " -days 3650" +
|
||||
" -extensions v3_ca -batch -out " + csr_name +
|
||||
" -utf8 -subj '/CN=" + name + "'")
|
||||
|
||||
extensions_filename = db_dir + "/openssl-exts"
|
||||
f = open(extensions_filename,'w')
|
||||
f.write(ext_text)
|
||||
f.close()
|
||||
|
||||
cert_name = dest_dir + "/"+ name + ".der"
|
||||
if not signer_key_filename:
|
||||
signer_key_filename = key_name;
|
||||
os.system ("openssl x509 -req -sha256 -days 3650 -in " + csr_name +
|
||||
" -signkey " + signer_key_filename +
|
||||
" -set_serial " + str(serial_num) +
|
||||
" -extfile " + extensions_filename +
|
||||
" -outform DER -out "+ cert_name)
|
||||
else:
|
||||
os.system ("openssl x509 -req -sha256 -days 3650 -in " + csr_name +
|
||||
" -CAkey " + signer_key_filename +
|
||||
" -CA " + signer_cert_filename + " -CAform DER " +
|
||||
" -set_serial " + str(serial_num) + " -out " + cert_name +
|
||||
" -outform DER -extfile " + extensions_filename)
|
||||
return key_name, cert_name
|
||||
|
||||
|
||||
|
||||
def generate_int_and_ee(db_dir, dest_dir, ca_key, ca_cert, name, int_ext_text,
|
||||
ee_ext_text, key_type = 'rsa'):
|
||||
"""
|
||||
Generate an intermediate and ee signed by the generated intermediate. The
|
||||
name of the intermediate files will be the name '.der' or '.key'. The name
|
||||
of the end entity files with be "ee-"+ name plus the appropiate prefixes.
|
||||
The serial number will be generated radomly so it is potentially possible
|
||||
to have problem (but very unlikely).
|
||||
|
||||
Arguments:
|
||||
db_dir -- location of the temporary params for the certificate
|
||||
dest_dir -- location of the x509 cert
|
||||
ca_key -- The filename of the key that will be used to sign the
|
||||
intermediate (PEM FORMAT)
|
||||
ca_cert -- The filename of the cert that will be used to sign the
|
||||
intermediate, it MUST be the private key for the ca_key.
|
||||
The file must be in DER format.
|
||||
name -- the common name for the intermediate, will match the prefix
|
||||
of the output intermediate. The ee will have the name
|
||||
prefixed with "ee-"
|
||||
int_ext_text -- the text for the x509 extensions to be added to the
|
||||
intermediate certificate
|
||||
ee_ext_text -- the text for the x509 extensions to be added to the
|
||||
end entity certificate
|
||||
key_type -- the type of key generated: potential values: 'rsa', 'dsa',
|
||||
or any of the curves found by 'openssl ecparam -list_curves'
|
||||
|
||||
output:
|
||||
int_key -- the filename of the intermeidate key file (PEM format)
|
||||
int_cert -- the filename of the intermediate certificate (DER format)
|
||||
ee_key -- the filename of the end entity key file (PEM format)
|
||||
ee_cert -- the filename of the end entity certficate (DER format)
|
||||
|
||||
"""
|
||||
[int_key, int_cert] = generate_cert_generic(db_dir, dest_dir,
|
||||
random.randint(100,40000000),
|
||||
key_type, "int-" + name,
|
||||
int_ext_text,
|
||||
ca_key, ca_cert)
|
||||
[ee_key, ee_cert] = generate_cert_generic(db_dir, dest_dir,
|
||||
random.randint(100,40000000),
|
||||
key_type, name,
|
||||
ee_ext_text, int_key, int_cert)
|
||||
|
||||
return int_key, int_cert, ee_key, ee_cert
|
||||
|
||||
|
89
security/manager/ssl/tests/unit/test_cert_signatures.js
Normal file
89
security/manager/ssl/tests/unit/test_cert_signatures.js
Normal file
@ -0,0 +1,89 @@
|
||||
// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/.
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* The purpose of this test is to verify that we correctly detect bad
|
||||
* signatures on tampered certificates. Eventually, we should also be
|
||||
* verifying that the error we return is the correct error.
|
||||
*
|
||||
* To regenerate the certificates for this test:
|
||||
*
|
||||
* cd security/manager/ssl/tests/unit/test_cert_signatures
|
||||
* ./generate.py
|
||||
* cd ../../../../../..
|
||||
* make -C $OBJDIR/security/manager/ssl/tests
|
||||
*
|
||||
* Check in the generated files. These steps are not done as part of the build
|
||||
* because we do not want to add a build-time dependency on the OpenSSL or NSS
|
||||
* tools or libraries built for the host platform.
|
||||
*/
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
|
||||
|
||||
const ca_usage = 'SSL CA';
|
||||
const int_usage = 'Client,Server,Sign,Encrypt,SSL CA,Status Responder';
|
||||
const ee_usage = 'Client,Server,Sign,Encrypt';
|
||||
|
||||
const cert2usage = {
|
||||
// certs without the "int" prefix are end entity certs.
|
||||
'int-rsa-valid': int_usage,
|
||||
'rsa-valid': ee_usage,
|
||||
'int-p384-valid': int_usage,
|
||||
'p384-valid': ee_usage,
|
||||
'int-dsa-valid': int_usage,
|
||||
'dsa-valid': ee_usage,
|
||||
|
||||
'rsa-valid-int-tampered-ee': "",
|
||||
'p384-valid-int-tampered-ee': "",
|
||||
'dsa-valid-int-tampered-ee': "",
|
||||
|
||||
'int-rsa-tampered': "",
|
||||
'rsa-tampered-int-valid-ee': "",
|
||||
'int-p384-tampered': "",
|
||||
'p384-tampered-int-valid-ee': "",
|
||||
'int-dsa-tampered': "",
|
||||
'dsa-tampered-int-valid-ee': "",
|
||||
|
||||
};
|
||||
|
||||
function load_ca(ca_name) {
|
||||
let ca_filename = ca_name + ".der";
|
||||
addCertFromFile(certdb, "test_cert_signatures/" + ca_filename, 'CTu,CTu,CTu');
|
||||
|
||||
do_print("ca_name=" + ca_name);
|
||||
let cert = certdb.findCertByNickname(null, ca_name);
|
||||
|
||||
let verified = {};
|
||||
let usages = {};
|
||||
cert.getUsagesString(true, verified, usages);
|
||||
do_check_eq(ca_usage, usages.value);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// Load the ca into mem
|
||||
load_ca("ca-rsa");
|
||||
load_ca("ca-p384");
|
||||
load_ca("ca-dsa");
|
||||
|
||||
// Load certs first
|
||||
for (let cert_name in cert2usage) {
|
||||
let cert_filename = cert_name + ".der";
|
||||
addCertFromFile(certdb, "test_cert_signatures/" + cert_filename, ',,');
|
||||
}
|
||||
|
||||
// Now do the checks
|
||||
for (let cert_name in cert2usage) {
|
||||
do_print("cert_name=" + cert_name);
|
||||
|
||||
let cert = certdb.findCertByNickname(null, cert_name);
|
||||
|
||||
let verified = {};
|
||||
let usages = {};
|
||||
cert.getUsagesString(true, verified, usages);
|
||||
do_check_eq(cert2usage[cert_name], usages.value);
|
||||
}
|
||||
}
|
BIN
security/manager/ssl/tests/unit/test_cert_signatures/ca-dsa.der
Normal file
BIN
security/manager/ssl/tests/unit/test_cert_signatures/ca-dsa.der
Normal file
Binary file not shown.
BIN
security/manager/ssl/tests/unit/test_cert_signatures/ca-p384.der
Normal file
BIN
security/manager/ssl/tests/unit/test_cert_signatures/ca-p384.der
Normal file
Binary file not shown.
BIN
security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.der
Normal file
BIN
security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.der
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
104
security/manager/ssl/tests/unit/test_cert_signatures/generate.py
Executable file
104
security/manager/ssl/tests/unit/test_cert_signatures/generate.py
Executable file
@ -0,0 +1,104 @@
|
||||
#!/usr/bin/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 tempfile, os, sys
|
||||
import random
|
||||
libpath = os.path.abspath('../psm_common_py')
|
||||
|
||||
sys.path.append(libpath)
|
||||
|
||||
import CertUtils
|
||||
|
||||
srcdir = os.getcwd()
|
||||
db = tempfile.mkdtemp()
|
||||
|
||||
CA_basic_constraints = "basicConstraints=critical,CA:TRUE\n"
|
||||
CA_limited_basic_constraints = "basicConstraints=critical,CA:TRUE, pathlen:0\n"
|
||||
EE_basic_constraints = "basicConstraints=CA:FALSE\n"
|
||||
|
||||
CA_min_ku = "keyUsage=critical, keyCertSign\n"
|
||||
CA_bad_ku = ("keyUsage=digitalSignature, nonRepudiation, keyEncipherment," +
|
||||
" dataEncipherment, keyAgreement, cRLSign\n")
|
||||
EE_full_ku = ("keyUsage=digitalSignature, nonRepudiation, keyEncipherment," +
|
||||
" dataEncipherment, keyAgreement, keyCertSign, cRLSign\n")
|
||||
|
||||
Server_eku= "extendedKeyUsage=critical,serverAuth,clientAuth\n"
|
||||
|
||||
pk_name = {'rsa': 'rsa', 'dsa': 'dsa', 'p384': 'secp384r1'}
|
||||
|
||||
|
||||
def tamper_cert(cert_name):
|
||||
f = open(cert_name, 'r+b')
|
||||
f.seek(-3, 2) # third byte from the end to ensure we only touch the
|
||||
# signature value. The location for the perturbation ensures that we are
|
||||
# modifying just the tbsCertificate without the need of parsing the
|
||||
# certificate. Also this guarantees that if a failure occurs it is because
|
||||
# of an invalid signature and not another field that might have become
|
||||
# invalid.
|
||||
b = bytearray(f.read(1))
|
||||
for i in range(len(b)):
|
||||
b[i] ^= 0x77
|
||||
f.seek(-1, 1)
|
||||
f.write(b)
|
||||
f.close()
|
||||
return 1
|
||||
|
||||
def generate_certs():
|
||||
|
||||
CertUtils.init_dsa(db)
|
||||
ee_ext_text = EE_basic_constraints + EE_full_ku
|
||||
for name, key_type in pk_name.iteritems():
|
||||
ca_name = "ca-" + name
|
||||
[ca_key, ca_cert] = CertUtils.generate_cert_generic(db,
|
||||
srcdir,
|
||||
random.randint(100,4000000),
|
||||
key_type,
|
||||
ca_name,
|
||||
CA_basic_constraints + CA_min_ku)
|
||||
|
||||
[valid_int_key, valid_int_cert, ee_key, ee_cert] = (
|
||||
CertUtils.generate_int_and_ee(db,
|
||||
srcdir,
|
||||
ca_key,
|
||||
ca_cert,
|
||||
name + "-valid",
|
||||
CA_basic_constraints,
|
||||
ee_ext_text,
|
||||
key_type) )
|
||||
|
||||
[int_key, int_cert] = CertUtils.generate_cert_generic(db,
|
||||
srcdir,
|
||||
random.randint(100,4000000),
|
||||
key_type,
|
||||
"int-" + name + "-tampered",
|
||||
ee_ext_text,
|
||||
ca_key,
|
||||
ca_cert)
|
||||
|
||||
|
||||
[ee_key, ee_cert] = CertUtils.generate_cert_generic(db,
|
||||
srcdir,
|
||||
random.randint(100,4000000),
|
||||
key_type,
|
||||
name + "-tampered-int-valid-ee",
|
||||
ee_ext_text,
|
||||
int_key,
|
||||
int_cert)
|
||||
#only tamper after ee has been generated
|
||||
tamper_cert(int_cert);
|
||||
|
||||
[ee_key, ee_cert] = CertUtils.generate_cert_generic(db,
|
||||
srcdir,
|
||||
random.randint(100,4000000),
|
||||
key_type,
|
||||
name + "-valid-int-tampered-ee",
|
||||
ee_ext_text,
|
||||
valid_int_key,
|
||||
valid_int_cert)
|
||||
tamper_cert(ee_cert);
|
||||
|
||||
|
||||
generate_certs()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -5,6 +5,7 @@ support-files =
|
||||
test_certificate_usages/**
|
||||
test_signed_apps/**
|
||||
tlsserver/**
|
||||
test_cert_signatures/**
|
||||
|
||||
[test_certificate_usages.js]
|
||||
# Bug 676972: test fails consistently on Android
|
||||
@ -30,3 +31,6 @@ skip-if = os == "android"
|
||||
# Bug 676972: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_sts_ipv4_ipv6.js]
|
||||
[test_cert_signatures.js]
|
||||
# Bug 676972: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
|
Loading…
Reference in New Issue
Block a user