1
1
import crypto , { KeyObject } from 'crypto' ;
2
2
import read from 'read' ;
3
+ import assert from 'assert' ;
4
+ import {
5
+ PUBLIC_KEY_ATTRIBUTE_NAME_MAPPING ,
6
+ SignatureType ,
7
+ } from './constants.js' ;
3
8
4
9
// A helper function that can be used to read the passphrase to decrypt a
5
10
// password-decrypted private key.
@@ -31,15 +36,62 @@ export function parsePemKey(
31
36
} ) ;
32
37
}
33
38
34
- export function getRawPublicKey ( publicKey : crypto . KeyObject ) {
35
- // Currently this is the only way for us to get the raw 32 bytes of the public key.
36
- return new Uint8Array (
37
- publicKey . export ( { type : 'spki' , format : 'der' } ) . slice ( - 32 )
39
+ function maybeGetSignatureType ( key : crypto . KeyObject ) : SignatureType | null {
40
+ switch ( key . asymmetricKeyType ) {
41
+ case 'ed25519' :
42
+ return SignatureType . Ed25519 ;
43
+ case 'ec' :
44
+ if ( key . asymmetricKeyDetails ?. namedCurve === 'prime256v1' ) {
45
+ return SignatureType . EcdsaP256SHA256 ;
46
+ }
47
+ break ;
48
+ default :
49
+ break ;
50
+ }
51
+ return null ;
52
+ }
53
+
54
+ export function isAsymmetricKeyTypeSupported ( key : crypto . KeyObject ) : boolean {
55
+ return maybeGetSignatureType ( key ) !== null ;
56
+ }
57
+
58
+ export function getSignatureType ( key : crypto . KeyObject ) : SignatureType {
59
+ const signatureType = maybeGetSignatureType ( key ) ;
60
+ assert (
61
+ signatureType !== null ,
62
+ 'Expected either "Ed25519" or "ECDSA P-256" key.'
38
63
) ;
64
+ return signatureType ;
65
+ }
66
+
67
+ export function getPublicKeyAttributeName ( key : crypto . KeyObject ) {
68
+ return PUBLIC_KEY_ATTRIBUTE_NAME_MAPPING . get ( getSignatureType ( key ) ) ! ;
39
69
}
40
70
41
- // Throws an error if the key is not a valid Ed25519 key of the specified type.
42
- export function checkIsValidEd25519Key (
71
+ export function getRawPublicKey ( publicKey : crypto . KeyObject ) {
72
+ const exportedKey = publicKey . export ( { type : 'spki' , format : 'der' } ) ;
73
+ switch ( getSignatureType ( publicKey ) ) {
74
+ case SignatureType . Ed25519 :
75
+ // Currently this is the only way for us to get the raw 32 bytes of the public key.
76
+ return new Uint8Array ( exportedKey . subarray ( - 32 ) ) ;
77
+ case SignatureType . EcdsaP256SHA256 : {
78
+ // The last 65 bytes are the raw bytes of the ECDSA P-256 public key.
79
+ // For the purposes of signing, we'd like to convert it to its compressed form that takes only 33 bytes.
80
+ const uncompressedKey = exportedKey . subarray ( - 65 ) ;
81
+ const compressedKey = crypto . ECDH . convertKey (
82
+ uncompressedKey ,
83
+ 'prime256v1' ,
84
+ /*inputEncoding=*/ undefined ,
85
+ /*outputEncoding=*/ undefined ,
86
+ 'compressed'
87
+ ) as Buffer ;
88
+ return new Uint8Array ( compressedKey ) ;
89
+ }
90
+ }
91
+ }
92
+
93
+ // Throws an error if the key is not a valid Ed25519 or ECDSA P-256 key of the specified type.
94
+ export function checkIsValidKey (
43
95
expectedKeyType : crypto . KeyObjectType ,
44
96
key : KeyObject
45
97
) {
@@ -49,9 +101,7 @@ export function checkIsValidEd25519Key(
49
101
) ;
50
102
}
51
103
52
- if ( key . asymmetricKeyType !== 'ed25519' ) {
53
- throw new Error (
54
- `Expected asymmetric key type to be "ed25519", but it was "${ key . asymmetricKeyType } ".`
55
- ) ;
104
+ if ( ! isAsymmetricKeyTypeSupported ( key ) ) {
105
+ throw new Error ( `Expected either "Ed25519" or "ECDSA P-256" key.` ) ;
56
106
}
57
107
}
0 commit comments