Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit44aec4a

Browse files
author
Alex Wilson
committed
#59 want support for SPKI fingerprint format
Reviewed by: Isaac Davis <isaac.davis@joyent.com>Reviewed by: Cody Peter Mello <cody.mello@joyent.com>
1 parent385ff11 commit44aec4a

File tree

8 files changed

+220
-54
lines changed

8 files changed

+220
-54
lines changed

‎README.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,17 @@ Parameters
174174

175175
Same as`this.toBuffer(format).toString()`.
176176

177-
###`Key#fingerprint([algorithm = 'sha256'])`
177+
###`Key#fingerprint([algorithm = 'sha256'[, hashType = 'ssh']])`
178178

179179
Creates a new`Fingerprint` object representing this Key's fingerprint.
180180

181181
Parameters
182182

183183
-`algorithm` -- String name of hash algorithm to use, valid options are`md5`,
184184
`sha1`,`sha256`,`sha384`,`sha512`
185+
-`hashType` -- String name of fingerprint hash type to use, valid options are
186+
`ssh` (the type of fingerprint used by OpenSSH, e.g. in
187+
`ssh-keygen`),`spki` (used by HPKP, some OpenSSL applications)
185188

186189
###`Key#createVerify([hashAlgorithm])`
187190

@@ -333,17 +336,23 @@ Parameters
333336

334337
##Fingerprints
335338

336-
###`parseFingerprint(fingerprint[,algorithms])`
339+
###`parseFingerprint(fingerprint[,options])`
337340

338341
Pre-parses a fingerprint, creating a`Fingerprint` object that can be used to
339342
quickly locate a key by using the`Fingerprint#matches` function.
340343

341344
Parameters
342345

343346
-`fingerprint` -- String, the fingerprint value, in any supported format
344-
-`algorithms` -- Optional list of strings, names of hash algorithms to limit
345-
support to. If`fingerprint` uses a hash algorithm not on
346-
this list, throws`InvalidAlgorithmError`.
347+
-`options` -- Optional Object, with properties:
348+
-`algorithms` -- Array of strings, names of hash algorithms to limit
349+
support to. If`fingerprint` uses a hash algorithm not on
350+
this list, throws`InvalidAlgorithmError`.
351+
-`hashType` -- String, the type of hash the fingerprint uses, either`ssh`
352+
or`spki` (normally auto-detected based on the format, but
353+
can be overridden)
354+
-`type` -- String, the entity this fingerprint identifies, either`key` or
355+
`certificate`
347356

348357
###`Fingerprint.isFingerprint(obj)`
349358

@@ -364,14 +373,19 @@ Parameters
364373
`base64`. If this`Fingerprint` uses the`md5` algorithm, the
365374
default format is`hex`. Otherwise, the default is`base64`.
366375

367-
###`Fingerprint#matches(key)`
376+
###`Fingerprint#matches(keyOrCertificate)`
368377

369-
Verifies whether or not this`Fingerprint` matches a given`Key`. This function
370-
uses double-hashing to avoid leaking timing information. Returns a boolean.
378+
Verifies whether or not this`Fingerprint` matches a given`Key` or
379+
`Certificate`. This function uses double-hashing to avoid leaking timing
380+
information. Returns a boolean.
381+
382+
Note that a`Key`-type Fingerprint will always return`false` if asked to match
383+
a`Certificate` and vice versa.
371384

372385
Parameters
373386

374-
-`key` -- a`Key` object, the key to match this fingerprint against
387+
-`keyOrCertificate` -- a`Key` object or`Certificate` object, the entity to
388+
match this fingerprint against
375389

376390
##Signatures
377391

‎bin/sshpk-conv

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env node
22
// -*- mode: js -*-
33
// vim: set filetype=javascript :
4-
// Copyright2015 Joyent, Inc.All rights reserved.
4+
// Copyright2018 Joyent, Inc.All rights reserved.
55

66
vardashdash=require('dashdash');
77
varsshpk=require('../lib/index');
@@ -47,6 +47,21 @@ var options = [
4747
type:'bool',
4848
help:'Print key metadata instead of converting'
4949
},
50+
{
51+
names:['fingerprint','F'],
52+
type:'bool',
53+
help:'Output key fingerprint'
54+
},
55+
{
56+
names:['hash','H'],
57+
type:'string',
58+
help:'Hash function to use for key fingeprint with -F'
59+
},
60+
{
61+
names:['spki','s'],
62+
type:'bool',
63+
help:'With -F, generates an SPKI fingerprint instead of SSH'
64+
},
5065
{
5166
names:['comment','c'],
5267
type:'string',
@@ -75,13 +90,17 @@ if (require.main === module) {
7590
varhelp=parser.help({}).trimRight();
7691
console.error('sshpk-conv: converts between SSH key formats\n');
7792
console.error(help);
78-
console.error('\navailable formats:');
93+
console.error('\navailablekeyformats:');
7994
console.error(' - pem, pkcs1 eg id_rsa');
8095
console.error(' - ssh eg id_rsa.pub');
8196
console.error(' - pkcs8 format you want for openssl');
8297
console.error(' - openssh like output of ssh-keygen -o');
8398
console.error(' - rfc4253 raw OpenSSH wire format');
8499
console.error(' - dnssec dnssec-keygen format');
100+
console.error('\navailable fingerprint formats:');
101+
console.error(' - hex colon-separated hex for SSH');
102+
console.error(' straight hex for SPKI');
103+
console.error(' - base64 SHA256:* format from OpenSSH');
85104
process.exit(1);
86105
}
87106

@@ -172,18 +191,7 @@ if (require.main === module) {
172191
if(opts.comment)
173192
key.comment=opts.comment;
174193

175-
if(!opts.identify){
176-
fmt=undefined;
177-
if(opts.outformat)
178-
fmt=opts.outformat;
179-
outFile.write(key.toBuffer(fmt));
180-
if(fmt==='ssh'||
181-
(!opts.private&&fmt===undefined))
182-
outFile.write('\n');
183-
outFile.once('drain',function(){
184-
process.exit(0);
185-
});
186-
}else{
194+
if(opts.identify){
187195
varkind='public';
188196
if(sshpk.PrivateKey.isPrivateKey(key))
189197
kind='private';
@@ -193,10 +201,38 @@ if (require.main === module) {
193201
console.log('ECDSA curve: %s',key.curve);
194202
if(key.comment)
195203
console.log('Comment: %s',key.comment);
196-
console.log('Fingerprint:');
197-
console.log(' '+key.fingerprint().toString());
198-
console.log(' '+key.fingerprint('md5').toString());
204+
console.log('SHA256 fingerprint: '+
205+
key.fingerprint('sha256').toString());
206+
console.log('MD5 fingerprint: '+
207+
key.fingerprint('md5').toString());
208+
console.log('SPKI-SHA256 fingerprint: '+
209+
key.fingerprint('sha256','spki').toString());
199210
process.exit(0);
211+
return;
200212
}
213+
214+
if(opts.fingerprint){
215+
varhash=opts.hash;
216+
vartype=opts.spki ?'spki' :'ssh';
217+
varformat=opts.outformat;
218+
varfp=key.fingerprint(hash,type).toString(format);
219+
outFile.write(fp);
220+
outFile.write('\n');
221+
outFile.once('drain',function(){
222+
process.exit(0);
223+
});
224+
return;
225+
}
226+
227+
fmt=undefined;
228+
if(opts.outformat)
229+
fmt=opts.outformat;
230+
outFile.write(key.toBuffer(fmt));
231+
if(fmt==='ssh'||
232+
(!opts.private&&fmt===undefined))
233+
outFile.write('\n');
234+
outFile.once('drain',function(){
235+
process.exit(0);
236+
});
201237
});
202238
}

‎lib/fingerprint.js

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright2015 Joyent, Inc.
1+
// Copyright2018 Joyent, Inc.
22

33
module.exports=Fingerprint;
44

@@ -8,6 +8,7 @@ var algs = require('./algs');
88
varcrypto=require('crypto');
99
varerrs=require('./errors');
1010
varKey=require('./key');
11+
varPrivateKey=require('./private-key');
1112
varCertificate=require('./certificate');
1213
varutils=require('./utils');
1314

@@ -26,11 +27,12 @@ function Fingerprint(opts) {
2627

2728
this.hash=opts.hash;
2829
this.type=opts.type;
30+
this.hashType=opts.hashType;
2931
}
3032

3133
Fingerprint.prototype.toString=function(format){
3234
if(format===undefined){
33-
if(this.algorithm==='md5')
35+
if(this.algorithm==='md5'||this.hashType==='spki')
3436
format='hex';
3537
else
3638
format='base64';
@@ -39,8 +41,12 @@ Fingerprint.prototype.toString = function (format) {
3941

4042
switch(format){
4143
case'hex':
44+
if(this.hashType==='spki')
45+
return(this.hash.toString('hex'));
4246
return(addColons(this.hash.toString('hex')));
4347
case'base64':
48+
if(this.hashType==='spki')
49+
return(this.hash.toString('base64'));
4450
return(sshBase64Format(this.algorithm,
4551
this.hash.toString('base64')));
4652
default:
@@ -50,14 +56,20 @@ Fingerprint.prototype.toString = function (format) {
5056

5157
Fingerprint.prototype.matches=function(other){
5258
assert.object(other,'key or certificate');
53-
if(this.type==='key'){
59+
if(this.type==='key'&&this.hashType!=='ssh'){
60+
utils.assertCompatible(other,Key,[1,7],'key with spki');
61+
if(PrivateKey.isPrivateKey(other)){
62+
utils.assertCompatible(other,PrivateKey,[1,6],
63+
'privatekey with spki support');
64+
}
65+
}elseif(this.type==='key'){
5466
utils.assertCompatible(other,Key,[1,0],'key');
5567
}else{
5668
utils.assertCompatible(other,Certificate,[1,0],
5769
'certificate');
5870
}
5971

60-
vartheirHash=other.hash(this.algorithm);
72+
vartheirHash=other.hash(this.algorithm,this.hashType);
6173
vartheirHash2=crypto.createHash(this.algorithm).
6274
update(theirHash).digest('base64');
6375

@@ -68,6 +80,11 @@ Fingerprint.prototype.matches = function (other) {
6880
return(this.hash2===theirHash2);
6981
};
7082

83+
/*JSSTYLED*/
84+
varbase64RE=/^[A-Za-z0-9+\/=]+$/;
85+
/*JSSTYLED*/
86+
varhexRE=/^[a-fA-F0-9]+$/;
87+
7188
Fingerprint.parse=function(fp,options){
7289
assert.string(fp,'fingerprint');
7390

@@ -81,13 +98,18 @@ Fingerprint.parse = function (fp, options) {
8198
options={};
8299
if(options.enAlgs!==undefined)
83100
enAlgs=options.enAlgs;
101+
if(options.algorithms!==undefined)
102+
enAlgs=options.algorithms;
84103
assert.optionalArrayOfString(enAlgs,'algorithms');
85104

105+
varhashType='ssh';
106+
if(options.hashType!==undefined)
107+
hashType=options.hashType;
108+
assert.string(hashType,'options.hashType');
109+
86110
varparts=fp.split(':');
87111
if(parts.length==2){
88112
alg=parts[0].toLowerCase();
89-
/*JSSTYLED*/
90-
varbase64RE=/^[A-Za-z0-9+\/=]+$/;
91113
if(!base64RE.test(parts[1]))
92114
throw(newFingerprintFormatError(fp));
93115
try{
@@ -107,15 +129,42 @@ Fingerprint.parse = function (fp, options) {
107129
return(p);
108130
});
109131
parts=parts.join('');
110-
/*JSSTYLED*/
111-
varmd5RE=/^[a-fA-F0-9]+$/;
112-
if(!md5RE.test(parts)||parts.length%2!==0)
132+
if(!hexRE.test(parts)||parts.length%2!==0)
113133
throw(newFingerprintFormatError(fp));
114134
try{
115135
hash=Buffer.from(parts,'hex');
116136
}catch(e){
117137
throw(newFingerprintFormatError(fp));
118138
}
139+
}else{
140+
if(hexRE.test(fp)){
141+
hash=Buffer.from(fp,'hex');
142+
}elseif(base64RE.test(fp)){
143+
hash=Buffer.from(fp,'base64');
144+
}else{
145+
throw(newFingerprintFormatError(fp));
146+
}
147+
148+
switch(hash.length){
149+
case32:
150+
alg='sha256';
151+
break;
152+
case16:
153+
alg='md5';
154+
break;
155+
case20:
156+
alg='sha1';
157+
break;
158+
case64:
159+
alg='sha512';
160+
break;
161+
default:
162+
throw(newFingerprintFormatError(fp));
163+
}
164+
165+
/* Plain hex/base64: guess it's probably SPKI unless told. */
166+
if(options.hashType===undefined)
167+
hashType='spki';
119168
}
120169

121170
if(alg===undefined)
@@ -133,7 +182,8 @@ Fingerprint.parse = function (fp, options) {
133182
return(newFingerprint({
134183
algorithm:alg,
135184
hash:hash,
136-
type:options.type||'key'
185+
type:options.type||'key',
186+
hashType:hashType
137187
}));
138188
};
139189

@@ -159,8 +209,9 @@ Fingerprint.isFingerprint = function (obj, ver) {
159209
* API versions for Fingerprint:
160210
* [1,0] -- initial ver
161211
* [1,1] -- first tagged ver
212+
* [1,2] -- hashType and spki support
162213
*/
163-
Fingerprint.prototype._sshpkApiVersion=[1,1];
214+
Fingerprint.prototype._sshpkApiVersion=[1,2];
164215

165216
Fingerprint._oldVersionDetect=function(obj){
166217
assert.func(obj.toString);

‎lib/formats/pkcs8.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Copyright2015 Joyent, Inc.
1+
// Copyright2018 Joyent, Inc.
22

33
module.exports={
44
read:read,
55
readPkcs8:readPkcs8,
66
write:write,
77
writePkcs8:writePkcs8,
8+
pkcs8ToBuffer:pkcs8ToBuffer,
89

910
readECDSACurve:readECDSACurve,
1011
writeECDSACurve:writeECDSACurve
@@ -412,6 +413,12 @@ function readPkcs8X25519Private(der) {
412413
return(newPrivateKey(key));
413414
}
414415

416+
functionpkcs8ToBuffer(key){
417+
varder=newasn1.BerWriter();
418+
writePkcs8(der,key);
419+
return(der.buffer);
420+
}
421+
415422
functionwritePkcs8(der,key){
416423
der.startSequence();
417424

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp