Skip to content

Commit 4d01aed

Browse files
author
Alex Wilson
committed
#39 Missing NULL in x509 RSA certs
Reviewed by: Cody Peter Mello <cody.mello@joyent.com> Approved by: Cody Peter Mello <cody.mello@joyent.com>
1 parent 69d24bc commit 4d01aed

File tree

2 files changed

+88
-21
lines changed

2 files changed

+88
-21
lines changed

lib/formats/x509.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ function writeTBSCert(cert, der) {
523523

524524
der.startSequence();
525525
der.writeOID(SIGN_ALGS[sig.algo]);
526+
if (sig.algo.match(/^rsa-/))
527+
der.writeNull();
526528
der.endSequence();
527529

528530
cert.issuer.toAsn1(der);

test/openssl-cmd.js

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ FPS.ecdsa = sshpk.parseFingerprint(
2020
FPS.ecdsa2 = sshpk.parseFingerprint(
2121
'SHA256:Kyu0EMqH8fzfp9RXKJ6kmsk9qKGBqVRtlOuk6bXfCEU');
2222

23+
var ASN1PARSE_LINE =
24+
/^\s*([0-9]*):d=([0-9]+)\s+hl=([0-9]+)\s+l=\s*([0-9]+)\s*([a-z]+):\s*([^:\[]+)\s*(\[[^\]]+\])?\s*(:.+)?$/;
25+
function asn1parse_line2obj(line) {
26+
var m = line.match(ASN1PARSE_LINE);
27+
if (!m)
28+
throw (new Error('Not a valid asn1parse output line'));
29+
var obj = {
30+
offset: parseInt(m[1], 10),
31+
depth: parseInt(m[2], 10),
32+
headerLength: parseInt(m[3], 10),
33+
length: parseInt(m[4], 10),
34+
type: m[5],
35+
tag: m[6].trim()
36+
};
37+
if (m[7])
38+
obj.valueType = m[7].slice(1, m[7].length - 1);
39+
if (m[8])
40+
obj.value = m[8].slice(1);
41+
return (obj);
42+
}
43+
2344
temp.track();
2445

2546
test('openssl version', function (t) {
@@ -306,19 +327,21 @@ function genTests() {
306327
var output = Buffer.concat(bufs).toString('utf8');
307328
var lines = output.split('\n');
308329
var foundString = false;
309-
lines.forEach(function (line) {
310-
if (line.indexOf('おはよう') !== -1) {
311-
t.strictEqual(
312-
line.indexOf('PRINTABLESTRING'),
313-
-1);
314-
t.strictEqual(
315-
line.indexOf('IA5STRING'),
316-
-1);
317-
t.notStrictEqual(
318-
line.indexOf('UTF8STRING'), -1);
330+
for (var i = 0; i < lines.length; ++i) {
331+
if (!lines[i])
332+
continue;
333+
var line = asn1parse_line2obj(lines[i]);
334+
if (line.tag === 'OBJECT' &&
335+
line.value === 'commonName') {
336+
var nline = asn1parse_line2obj(
337+
lines[i + 1]);
338+
t.strictEqual(nline.value,
339+
'おはよう', 'CN should be set');
340+
t.strictEqual(nline.tag, 'UTF8STRING',
341+
'CN should be a utf8string');
319342
foundString = true;
320343
}
321-
});
344+
}
322345
t.ok(foundString);
323346
t.end();
324347
});
@@ -342,18 +365,21 @@ function genTests() {
342365
var output = Buffer.concat(bufs).toString('utf8');
343366
var lines = output.split('\n');
344367
var foundString = false;
345-
lines.forEach(function (line) {
346-
if (line.indexOf('foo_bar@') !== -1) {
347-
t.strictEqual(
348-
line.indexOf('PRINTABLESTRING'),
349-
-1);
350-
t.strictEqual(
351-
line.indexOf('UTF8STRING'), -1);
352-
t.notStrictEqual(
353-
line.indexOf('IA5STRING'), -1);
368+
for (var i = 0; i < lines.length; ++i) {
369+
if (!lines[i])
370+
continue;
371+
var line = asn1parse_line2obj(lines[i]);
372+
if (line.tag === 'OBJECT' &&
373+
line.value === 'commonName') {
374+
var nline = asn1parse_line2obj(
375+
lines[i + 1]);
376+
t.strictEqual(nline.value,
377+
'foo_bar@', 'CN should be set');
378+
t.strictEqual(nline.tag, 'IA5STRING',
379+
'CN should be a ia5string');
354380
foundString = true;
355381
}
356-
});
382+
}
357383
t.ok(foundString);
358384
t.end();
359385
});
@@ -391,6 +417,45 @@ function genTests() {
391417
});
392418
});
393419

420+
test('nulls in x509 rsa certs (#39)', function (t) {
421+
var pem = fs.readFileSync(path.join(testDir, 'id_rsa'));
422+
var key = sshpk.parsePrivateKey(pem, 'pkcs1');
423+
424+
var id = sshpk.identityFromDN('cn=foobar');
425+
var cert = sshpk.createSelfSignedCertificate(id, key);
426+
var certPem = cert.toBuffer('pem');
427+
428+
var kid = spawn('openssl', ['asn1parse']);
429+
var bufs = [];
430+
kid.stdout.on('data', bufs.push.bind(bufs));
431+
kid.on('close', function (rc) {
432+
t.equal(rc, 0, 'openssl command exit status 0');
433+
var output = Buffer.concat(bufs).toString('utf8');
434+
var lines = output.split('\n');
435+
var found = false;
436+
for (var i = 0; i < lines.length; ++i) {
437+
if (lines[i].length < 1)
438+
continue;
439+
var line = asn1parse_line2obj(lines[i]);
440+
if (line.type === 'prim' && line.tag === 'OBJECT' &&
441+
line.value === 'sha256WithRSAEncryption') {
442+
var nline = asn1parse_line2obj(lines[i + 1]);
443+
t.strictEqual(nline.tag, 'NULL',
444+
'null value must follow RSA OID');
445+
t.strictEqual(nline.type, 'prim',
446+
'null should be primitive');
447+
t.strictEqual(nline.depth, line.depth,
448+
'null should be at same depth as RSA OID');
449+
found = true;
450+
}
451+
}
452+
t.ok(found, 'should have an RSA OID');
453+
t.end();
454+
});
455+
kid.stdin.write(certPem);
456+
kid.stdin.end();
457+
});
458+
394459
test('utf8string in issuer DN (#40)', function (t) {
395460
var pem = fs.readFileSync(path.join(testDir, 'id_rsa'));
396461
var ikey = sshpk.parsePrivateKey(pem, 'pkcs1');

0 commit comments

Comments
 (0)