2727import java .security .spec .InvalidKeySpecException ;
2828import java .security .spec .PKCS8EncodedKeySpec ;
2929import java .util .ArrayList ;
30+ import java .util .Arrays ;
3031import java .util .Base64 ;
3132import java .util .Collections ;
3233import java .util .List ;
@@ -91,6 +92,36 @@ final class PemPrivateKeyParser {
9192 */
9293 private static final int [] RSA_ALGORITHM = { 0x2A , 0x86 , 0x48 , 0x86 , 0xF7 , 0x0D , 0x01 , 0x01 , 0x01 };
9394
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+
94125 /**
95126 * ASN.1 encoded object identifier {@literal 1.2.840.10045.2.1}.
96127 */
@@ -132,10 +163,10 @@ private static int[] getEcParameters(DerElement parameters) {
132163 DerElement contents = DerElement .of (parameters .getContents ());
133164 Assert .state (contents .isType (ValueType .PRIMITIVE , TagType .OBJECT_IDENTIFIER ),
134165 "Key spec parameters should contain object identifier" );
135- return getEcParameters (contents .getContents ());
166+ return getOid (contents .getContents ());
136167 }
137168
138- private static int [] getEcParameters (ByteBuffer bytes ) {
169+ private static int [] getOid (ByteBuffer bytes ) {
139170 int [] result = new int [bytes .remaining ()];
140171 for (int i = 0 ; i < result .length ; i ++) {
141172 result [i ] = bytes .get () & 0xFF ;
@@ -160,7 +191,55 @@ private static PKCS8EncodedKeySpec createKeySpecForAlgorithm(byte[] bytes, int[]
160191 }
161192
162193 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+ }
164243 }
165244
166245 private static PKCS8EncodedKeySpec createKeySpecForPkcs8Encrypted (byte [] bytes , String password ) {
@@ -231,6 +310,15 @@ private static byte[] decodeBase64(String content) {
231310
232311 private PrivateKey parse (byte [] bytes , String password ) {
233312 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+ }
234322 for (String algorithm : this .algorithms ) {
235323 try {
236324 KeyFactory keyFactory = KeyFactory .getInstance (algorithm );
0 commit comments