Add ext_key_usage to getPeerCertificate
This commit is contained in:
parent
6cdeb3b3fd
commit
6c32e155d3
@ -30,6 +30,7 @@ static Persistent<String> valid_to_symbol;
|
||||
static Persistent<String> fingerprint_symbol;
|
||||
static Persistent<String> name_symbol;
|
||||
static Persistent<String> version_symbol;
|
||||
static Persistent<String> ext_key_usage_symbol;
|
||||
|
||||
|
||||
void SecureContext::Initialize(Handle<Object> target) {
|
||||
@ -695,6 +696,20 @@ Handle<Value> Connection::GetPeerCertificate(const Arguments& args) {
|
||||
|
||||
info->Set(fingerprint_symbol, String::New(fingerprint));
|
||||
}
|
||||
|
||||
STACK_OF(ASN1_OBJECT) *eku = (STACK_OF(ASN1_OBJECT) *)X509_get_ext_d2i(peer_cert, NID_ext_key_usage, NULL, NULL);
|
||||
if (eku != NULL) {
|
||||
Local<Array> ext_key_usage = Array::New();
|
||||
|
||||
for (int i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
OBJ_obj2txt(buf, sizeof(buf) - 1, sk_ASN1_OBJECT_value(eku, i), 1);
|
||||
ext_key_usage->Set(Integer::New(i), String::New(buf));
|
||||
}
|
||||
|
||||
sk_ASN1_OBJECT_pop_free(eku, ASN1_OBJECT_free);
|
||||
info->Set(ext_key_usage_symbol, ext_key_usage);
|
||||
}
|
||||
|
||||
X509_free(peer_cert);
|
||||
}
|
||||
@ -2683,6 +2698,7 @@ void InitCrypto(Handle<Object> target) {
|
||||
fingerprint_symbol = NODE_PSYMBOL("fingerprint");
|
||||
name_symbol = NODE_PSYMBOL("name");
|
||||
version_symbol = NODE_PSYMBOL("version");
|
||||
ext_key_usage_symbol = NODE_PSYMBOL("ext_key_usage");
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
32
test/fixtures/keys/Makefile
vendored
32
test/fixtures/keys/Makefile
vendored
@ -1,4 +1,4 @@
|
||||
all: agent1-cert.pem agent2-cert.pem agent3-cert.pem
|
||||
all: agent1-cert.pem agent2-cert.pem agent3-cert.pem agent4-cert.pem
|
||||
|
||||
|
||||
#
|
||||
@ -82,13 +82,39 @@ agent3-cert.pem: agent3-csr.pem ca2-cert.pem ca2-key.pem
|
||||
agent3-verify: agent3-cert.pem ca2-cert.pem
|
||||
openssl verify -CAfile ca2-cert.pem agent3-cert.pem
|
||||
|
||||
|
||||
#
|
||||
# agent4 is signed by ca2 (client cert)
|
||||
#
|
||||
|
||||
agent4-key.pem:
|
||||
openssl genrsa -out agent4-key.pem
|
||||
|
||||
agent4-csr.pem: agent4.cnf agent4-key.pem
|
||||
openssl req -new -config agent4.cnf -key agent4-key.pem -out agent4-csr.pem
|
||||
|
||||
agent4-cert.pem: agent4-csr.pem ca2-cert.pem ca2-key.pem
|
||||
openssl x509 -req \
|
||||
-passin "pass:password" \
|
||||
-in agent4-csr.pem \
|
||||
-CA ca2-cert.pem \
|
||||
-CAkey ca2-key.pem \
|
||||
-CAcreateserial \
|
||||
-extfile agent4.cnf \
|
||||
-extensions ext_key_usage \
|
||||
-out agent4-cert.pem
|
||||
|
||||
agent4-verify: agent4-cert.pem ca2-cert.pem
|
||||
openssl verify -CAfile ca2-cert.pem agent4-cert.pem
|
||||
|
||||
|
||||
# TODO: agent on CRL
|
||||
|
||||
|
||||
clean:
|
||||
rm -f *.pem *.srl
|
||||
|
||||
test: agent1-verify agent2-verify agent3-verify
|
||||
test: agent1-verify agent2-verify agent3-verify agent4-verify
|
||||
|
||||
|
||||
.PHONY: all clean test agent1-verify agent2-verify agent3-verify
|
||||
.PHONY: all clean test agent1-verify agent2-verify agent3-verify agent4-verify
|
||||
|
15
test/fixtures/keys/agent4-cert.pem
vendored
Normal file
15
test/fixtures/keys/agent4-cert.pem
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICSDCCAbGgAwIBAgIJAND4S4oV8e77MA0GCSqGSIb3DQEBBQUAMHoxCzAJBgNV
|
||||
BAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UEBxMCU0YxDzANBgNVBAoTBkpveWVu
|
||||
dDEQMA4GA1UECxMHTm9kZS5qczEMMAoGA1UEAxMDY2EyMSAwHgYJKoZIhvcNAQkB
|
||||
FhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0xMTAxMjYyMzMzMjZaFw0xMTAyMjUyMzMz
|
||||
MjZaMH0xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UEBxMCU0YxDzAN
|
||||
BgNVBAoTBkpveWVudDEQMA4GA1UECxMHTm9kZS5qczEPMA0GA1UEAxMGYWdlbnQ0
|
||||
MSAwHgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzBcMA0GCSqGSIb3DQEB
|
||||
AQUAA0sAMEgCQQDAtcMgUqWCoCMI7ACMVbykoMbXvLwNHhB1/cApRFbXUd3SgDEz
|
||||
RGKrqZkcT8I1b5IlUwWVQOzN7G8LHijrb05hAgMBAAGjFzAVMBMGA1UdJQQMMAoG
|
||||
CCsGAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4GBAAjwjr91RV7xLD4j+xB4Ab0iMRx3
|
||||
fIb/vizhnWOHMXHp/CuUZcm0k2/lZqlGpLIUbhuUuglol/GyMYpL0l+4usUU5ayQ
|
||||
r5vOdRI5fo6WnwAlDvpLTJxN6exB3TxRqPu5WGI5t6NIDThJChpXXTuG9Auw+Lk+
|
||||
p+Q6Te22clo/XeUj
|
||||
-----END CERTIFICATE-----
|
10
test/fixtures/keys/agent4-csr.pem
vendored
Normal file
10
test/fixtures/keys/agent4-csr.pem
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBXTCCAQcCAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQH
|
||||
EwJTRjEPMA0GA1UEChMGSm95ZW50MRAwDgYDVQQLEwdOb2RlLmpzMQ8wDQYDVQQD
|
||||
EwZhZ2VudDQxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMFwwDQYJ
|
||||
KoZIhvcNAQEBBQADSwAwSAJBAMC1wyBSpYKgIwjsAIxVvKSgxte8vA0eEHX9wClE
|
||||
VtdR3dKAMTNEYqupmRxPwjVvkiVTBZVA7M3sbwseKOtvTmECAwEAAaAlMCMGCSqG
|
||||
SIb3DQEJBzEWExRBIGNoYWxsZW5nZSBwYXNzd29yZDANBgkqhkiG9w0BAQUFAANB
|
||||
AB8lvAXSHFf+ABRubFGuTuJse8omIJ1vRXuhY345qiObEDPkSVOj4LYUjBlE6S3V
|
||||
1TVdfQLBqcLJPY8zG66fjKI=
|
||||
-----END CERTIFICATE REQUEST-----
|
9
test/fixtures/keys/agent4-key.pem
vendored
Normal file
9
test/fixtures/keys/agent4-key.pem
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBOQIBAAJBAMC1wyBSpYKgIwjsAIxVvKSgxte8vA0eEHX9wClEVtdR3dKAMTNE
|
||||
YqupmRxPwjVvkiVTBZVA7M3sbwseKOtvTmECAwEAAQI/EVBDN6Q1OoconqSVaAZL
|
||||
7H6FXtyWCJeq4u7pVMvPAYkxe4MQOqAYmHCQlozJBOjwfpi/09KccZ7Ssi80Tc2d
|
||||
AiEA3tOQX52YHptUdW5gSm4/y8dlhfita//SPkqexECYDF8CIQDdZmQtguBMvHS/
|
||||
Mjk5ypRo0mU4G8ZGL7ML1q0GMFKdPwIgP/+VvNCfq1LDrEK6Z0ZJDndDonntHVLJ
|
||||
iNiXxxgiU5MCIFwrKxszN9NaRTPvYZlod14n8JFqJqHDa8NK7J798PabAiEAlwke
|
||||
T6UdRvxUZPDW5XRUVftcDygFvF05Hfrr8ziVc88=
|
||||
-----END RSA PRIVATE KEY-----
|
21
test/fixtures/keys/agent4.cnf
vendored
Normal file
21
test/fixtures/keys/agent4.cnf
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
[ req ]
|
||||
default_bits = 1024
|
||||
days = 36500
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
prompt = no
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = US
|
||||
ST = CA
|
||||
L = SF
|
||||
O = Joyent
|
||||
OU = Node.js
|
||||
CN = agent4
|
||||
emailAddress = ry@tinyclouds.org
|
||||
|
||||
[ req_attributes ]
|
||||
challengePassword = A challenge password
|
||||
|
||||
[ ext_key_usage ]
|
||||
extendedKeyUsage = clientAuth
|
2
test/fixtures/keys/ca2-cert.srl
vendored
2
test/fixtures/keys/ca2-cert.srl
vendored
@ -1 +1 @@
|
||||
D0F84B8A15F1EEF9
|
||||
D0F84B8A15F1EEFB
|
||||
|
153
test/simple/test-tls-ext-key-usage.js
Normal file
153
test/simple/test-tls-ext-key-usage.js
Normal file
@ -0,0 +1,153 @@
|
||||
// There is a bug with 'openssl s_server' which makes it not flush certain
|
||||
// important events to stdout when done over a pipe. Therefore we skip this
|
||||
// test for all openssl versions less than 1.0.0.
|
||||
if (!process.versions.openssl ||
|
||||
parseInt(process.versions.openssl[0]) < 1) {
|
||||
console.error("Skipping due to old OpenSSL version.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
||||
var common = require('../common');
|
||||
var join = require('path').join;
|
||||
var net = require('net');
|
||||
var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
var crypto = require('crypto');
|
||||
var tls = require('tls');
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
// FIXME: Avoid the common PORT as this test currently hits a C-level
|
||||
// assertion error with node_g. The program aborts without HUPing
|
||||
// the openssl s_server thus causing many tests to fail with
|
||||
// EADDRINUSE.
|
||||
var PORT = common.PORT + 5;
|
||||
|
||||
var connections = 0;
|
||||
|
||||
var keyfn = join(common.fixturesDir, 'keys', 'agent4-key.pem');
|
||||
var key = fs.readFileSync(keyfn).toString();
|
||||
|
||||
var certfn = join(common.fixturesDir, 'keys', 'agent4-cert.pem');
|
||||
var cert = fs.readFileSync(certfn).toString();
|
||||
|
||||
var server = spawn('openssl', ['s_server',
|
||||
'-accept', PORT,
|
||||
'-cert', certfn,
|
||||
'-key', keyfn]);
|
||||
server.stdout.pipe(process.stdout);
|
||||
server.stderr.pipe(process.stdout);
|
||||
|
||||
|
||||
var state = 'WAIT-ACCEPT';
|
||||
|
||||
var serverStdoutBuffer = '';
|
||||
server.stdout.setEncoding('utf8');
|
||||
server.stdout.on('data', function(s) {
|
||||
serverStdoutBuffer += s;
|
||||
console.error(state);
|
||||
switch (state) {
|
||||
case 'WAIT-ACCEPT':
|
||||
if (/ACCEPT/g.test(serverStdoutBuffer)) {
|
||||
// Give s_server half a second to start up.
|
||||
setTimeout(startClient, 500);
|
||||
state = 'WAIT-HELLO';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'WAIT-HELLO':
|
||||
if (/hello/g.test(serverStdoutBuffer)) {
|
||||
|
||||
// End the current SSL connection and exit.
|
||||
// See s_server(1ssl).
|
||||
server.stdin.write('Q');
|
||||
|
||||
state = 'WAIT-SERVER-CLOSE';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var timeout = setTimeout(function () {
|
||||
server.kill();
|
||||
process.exit(1);
|
||||
}, 5000);
|
||||
|
||||
var gotWriteCallback = false;
|
||||
var serverExitCode = -1;
|
||||
|
||||
server.on('exit', function(code) {
|
||||
serverExitCode = code;
|
||||
clearTimeout(timeout);
|
||||
});
|
||||
|
||||
|
||||
function startClient() {
|
||||
var s = new net.Stream();
|
||||
|
||||
var sslcontext = crypto.createCredentials({key: key, cert: cert});
|
||||
sslcontext.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
|
||||
|
||||
var pair = tls.createSecurePair(sslcontext, false);
|
||||
|
||||
assert.ok(pair.encrypted.writable);
|
||||
assert.ok(pair.cleartext.writable);
|
||||
|
||||
pair.encrypted.pipe(s);
|
||||
s.pipe(pair.encrypted);
|
||||
|
||||
s.connect(PORT);
|
||||
|
||||
s.on('connect', function() {
|
||||
console.log('client connected');
|
||||
});
|
||||
|
||||
pair.on('secure', function() {
|
||||
console.log('client: connected+secure!');
|
||||
console.log('client pair.cleartext.getPeerCertificate(): %j',
|
||||
pair.cleartext.getPeerCertificate());
|
||||
|
||||
// "TLS Web Client Authentication"
|
||||
assert.equal(pair.cleartext.getPeerCertificate().ext_key_usage.length, 1)
|
||||
assert.equal(pair.cleartext.getPeerCertificate().ext_key_usage[0], '1.3.6.1.5.5.7.3.2')
|
||||
|
||||
console.log('client pair.cleartext.getCipher(): %j',
|
||||
pair.cleartext.getCipher());
|
||||
setTimeout(function() {
|
||||
pair.cleartext.write('hello\r\n', function () {
|
||||
gotWriteCallback = true;
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
pair.cleartext.on('data', function(d) {
|
||||
console.log('cleartext: %s', d.toString());
|
||||
});
|
||||
|
||||
s.on('close', function() {
|
||||
console.log('client close');
|
||||
});
|
||||
|
||||
pair.encrypted.on('error', function(err) {
|
||||
console.log('encrypted error: ' + err);
|
||||
});
|
||||
|
||||
s.on('error', function(err) {
|
||||
console.log('socket error: ' + err);
|
||||
});
|
||||
|
||||
pair.on('error', function(err) {
|
||||
console.log('secure error: ' + err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
process.on('exit', function() {
|
||||
assert.equal(0, serverExitCode);
|
||||
assert.equal('WAIT-SERVER-CLOSE', state);
|
||||
assert.ok(gotWriteCallback);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user