27
27
import java .security .spec .InvalidKeySpecException ;
28
28
import java .security .spec .PKCS8EncodedKeySpec ;
29
29
import java .util .ArrayList ;
30
+ import java .util .Arrays ;
30
31
import java .util .Base64 ;
31
32
import java .util .Collections ;
32
33
import java .util .List ;
@@ -91,6 +92,36 @@ final class PemPrivateKeyParser {
91
92
*/
92
93
private static final int [] RSA_ALGORITHM = { 0x2A , 0x86 , 0x48 , 0x86 , 0xF7 , 0x0D , 0x01 , 0x01 , 0x01 };
93
94
95
+ /**
96
+ * ASN.1 encoded object identifier {@literal 1.2.840.113549.1.1.10}.
97
+ */
98
+ private static final int [] RSASSA_PSS_ALGORITHM = { 0x2a , 0x86 , 0x48 , 0x86 , 0xf7 , 0x0d , 0x01 , 0x01 , 0x0a };
99
+
100
+ /**
101
+ * ASN.1 encoded object identifier {@literal 1.2.840.10040.4.1}.
102
+ */
103
+ private static final int [] DSA_ALGORITHM = { 0x2a , 0x86 , 0x48 , 0xce , 0x38 , 0x04 , 0x01 };
104
+
105
+ /**
106
+ * ASN.1 encoded object identifier {@literal 1.3.101.110}.
107
+ */
108
+ private static final int [] X25519_ALGORITHM = { 0x2b , 0x65 , 0x6e };
109
+
110
+ /**
111
+ * ASN.1 encoded object identifier {@literal 1.3.101.111}.
112
+ */
113
+ private static final int [] X448_ALGORITHM = { 0x2b , 0x65 , 0x6f };
114
+
115
+ /**
116
+ * ASN.1 encoded object identifier {@literal 1.3.101.112}.
117
+ */
118
+ private static final int [] ED448_ALGORITHM = { 0x2b , 0x65 , 0x70 };
119
+
120
+ /**
121
+ * ASN.1 encoded object identifier {@literal 1.3.101.113}.
122
+ */
123
+ private static final int [] ED25519_ALGORITHM = { 0x2b , 0x65 , 0x71 };
124
+
94
125
/**
95
126
* ASN.1 encoded object identifier {@literal 1.2.840.10045.2.1}.
96
127
*/
@@ -132,10 +163,10 @@ private static int[] getEcParameters(DerElement parameters) {
132
163
DerElement contents = DerElement .of (parameters .getContents ());
133
164
Assert .state (contents .isType (ValueType .PRIMITIVE , TagType .OBJECT_IDENTIFIER ),
134
165
"Key spec parameters should contain object identifier" );
135
- return getEcParameters (contents .getContents ());
166
+ return getOid (contents .getContents ());
136
167
}
137
168
138
- private static int [] getEcParameters (ByteBuffer bytes ) {
169
+ private static int [] getOid (ByteBuffer bytes ) {
139
170
int [] result = new int [bytes .remaining ()];
140
171
for (int i = 0 ; i < result .length ; i ++) {
141
172
result [i ] = bytes .get () & 0xFF ;
@@ -160,7 +191,55 @@ private static PKCS8EncodedKeySpec createKeySpecForAlgorithm(byte[] bytes, int[]
160
191
}
161
192
162
193
private static PKCS8EncodedKeySpec createKeySpecForPkcs8 (byte [] bytes , String password ) {
163
- return new PKCS8EncodedKeySpec (bytes );
194
+ DerElement ecPrivateKey = DerElement .of (bytes );
195
+ Assert .state (ecPrivateKey .isType (ValueType .ENCODED , TagType .SEQUENCE ),
196
+ "Key spec should be an ASN.1 encoded sequence" );
197
+ DerElement version = DerElement .of (ecPrivateKey .getContents ());
198
+ Assert .state (version != null && version .isType (ValueType .PRIMITIVE , TagType .INTEGER ),
199
+ "Key spec should start with version" );
200
+ DerElement sequence = DerElement .of (ecPrivateKey .getContents ());
201
+ Assert .state (sequence != null && sequence .isType (ValueType .ENCODED , TagType .SEQUENCE ),
202
+ "Key spec should contain private key" );
203
+ DerElement algorithmIdentifier = DerElement .of (sequence .getContents ());
204
+ Assert .state (
205
+ algorithmIdentifier != null
206
+ && algorithmIdentifier .isType (ValueType .PRIMITIVE , TagType .OBJECT_IDENTIFIER ),
207
+ "Key spec container object identifier" );
208
+ int [] oid = getOid (algorithmIdentifier .getContents ());
209
+ String algorithmName = getAlgorithm (oid );
210
+ if (algorithmName != null ) {
211
+ return new PKCS8EncodedKeySpec (bytes , algorithmName );
212
+ }
213
+ else {
214
+ return new PKCS8EncodedKeySpec (bytes );
215
+ }
216
+ }
217
+
218
+ private static String getAlgorithm (int [] oid ) {
219
+ if (oid == null ) {
220
+ return null ;
221
+ }
222
+ if (Arrays .equals (RSA_ALGORITHM , oid )) {
223
+ return "RSA" ;
224
+ }
225
+ else if (Arrays .equals (RSASSA_PSS_ALGORITHM , oid )) {
226
+ return "RSASSA-PSS" ;
227
+ }
228
+ else if (Arrays .equals (DSA_ALGORITHM , oid )) {
229
+ return "DSA" ;
230
+ }
231
+ else if (Arrays .equals (ED448_ALGORITHM , oid ) || Arrays .equals (ED25519_ALGORITHM , oid )) {
232
+ return "EdDSA" ;
233
+ }
234
+ else if (Arrays .equals (X448_ALGORITHM , oid ) || Arrays .equals (X25519_ALGORITHM , oid )) {
235
+ return "XDH" ;
236
+ }
237
+ else if (Arrays .equals (EC_ALGORITHM , oid )) {
238
+ return "EC" ;
239
+ }
240
+ else {
241
+ return null ;
242
+ }
164
243
}
165
244
166
245
private static PKCS8EncodedKeySpec createKeySpecForPkcs8Encrypted (byte [] bytes , String password ) {
@@ -231,6 +310,15 @@ private static byte[] decodeBase64(String content) {
231
310
232
311
private PrivateKey parse (byte [] bytes , String password ) {
233
312
PKCS8EncodedKeySpec keySpec = this .keySpecFactory .apply (bytes , password );
313
+ if (keySpec .getAlgorithm () != null ) {
314
+ try {
315
+ KeyFactory keyFactory = KeyFactory .getInstance (keySpec .getAlgorithm ());
316
+ return keyFactory .generatePrivate (keySpec );
317
+ }
318
+ catch (InvalidKeySpecException | NoSuchAlgorithmException ex ) {
319
+ // Ignore
320
+ }
321
+ }
234
322
for (String algorithm : this .algorithms ) {
235
323
try {
236
324
KeyFactory keyFactory = KeyFactory .getInstance (algorithm );
0 commit comments