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) {
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);
}
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
-all: agent1-cert.pem agent2-cert.pem agent3-cert.pem
+all: agent1-cert.pem agent2-cert.pem agent3-cert.pem agent4-cert.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
--- /dev/null
+// 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);
+});