11/*
2- * Copyright 2012-2023 the original author or authors.
2+ * Copyright 2012-2024 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
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 ;
33+ import java .util .HashMap ;
34+ import java .util .HexFormat ;
3235import java .util .List ;
36+ import java .util .Map ;
3337import java .util .function .BiFunction ;
3438import java .util .regex .Matcher ;
3539import java .util .regex .Pattern ;
@@ -73,6 +77,26 @@ final class PemPrivateKeyParser {
7377
7478 public static final int BASE64_TEXT_GROUP = 1 ;
7579
80+ private static final EncodedOid RSA_ALGORITHM = EncodedOid .OID_1_2_840_113549_1_1_1 ;
81+
82+ private static final EncodedOid ELLIPTIC_CURVE_ALGORITHM = EncodedOid .OID_1_2_840_10045_2_1 ;
83+
84+ private static final EncodedOid ELLIPTIC_CURVE_384_BIT = EncodedOid .OID_1_3_132_0_34 ;
85+
86+ private static final Map <EncodedOid , String > ALGORITHMS ;
87+ static {
88+ Map <EncodedOid , String > algorithms = new HashMap <>();
89+ algorithms .put (EncodedOid .OID_1_2_840_113549_1_1_1 , "RSA" );
90+ algorithms .put (EncodedOid .OID_1_2_840_113549_1_1_10 , "RSA" );
91+ algorithms .put (EncodedOid .OID_1_2_840_10040_4_1 , "DSA" );
92+ algorithms .put (EncodedOid .OID_1_3_101_110 , "XDH" );
93+ algorithms .put (EncodedOid .OID_1_3_101_111 , "XDH" );
94+ algorithms .put (EncodedOid .OID_1_3_101_112 , "EdDSA" );
95+ algorithms .put (EncodedOid .OID_1_3_101_113 , "EdDSA" );
96+ algorithms .put (EncodedOid .OID_1_2_840_10045_2_1 , "EC" );
97+ ALGORITHMS = Collections .unmodifiableMap (algorithms );
98+ }
99+
76100 private static final List <PemParser > PEM_PARSERS ;
77101 static {
78102 List <PemParser > parsers = new ArrayList <>();
@@ -86,21 +110,6 @@ final class PemPrivateKeyParser {
86110 PEM_PARSERS = Collections .unmodifiableList (parsers );
87111 }
88112
89- /**
90- * ASN.1 encoded object identifier {@literal 1.2.840.113549.1.1.1}.
91- */
92- private static final int [] RSA_ALGORITHM = { 0x2A , 0x86 , 0x48 , 0x86 , 0xF7 , 0x0D , 0x01 , 0x01 , 0x01 };
93-
94- /**
95- * ASN.1 encoded object identifier {@literal 1.2.840.10045.2.1}.
96- */
97- private static final int [] EC_ALGORITHM = { 0x2a , 0x86 , 0x48 , 0xce , 0x3d , 0x02 , 0x01 };
98-
99- /**
100- * ASN.1 encoded object identifier {@literal 1.3.132.0.34}.
101- */
102- private static final int [] EC_PARAMETERS = { 0x2b , 0x81 , 0x04 , 0x00 , 0x22 };
103-
104113 private PemPrivateKeyParser () {
105114 }
106115
@@ -121,29 +130,22 @@ private static PKCS8EncodedKeySpec createKeySpecForSec1Ec(byte[] bytes, String p
121130 Assert .state (privateKey != null && privateKey .isType (ValueType .PRIMITIVE , TagType .OCTET_STRING ),
122131 "Key spec should contain private key" );
123132 DerElement parameters = DerElement .of (ecPrivateKey .getContents ());
124- return createKeySpecForAlgorithm (bytes , EC_ALGORITHM , getEcParameters (parameters ));
133+ return createKeySpecForAlgorithm (bytes , ELLIPTIC_CURVE_ALGORITHM , getEcParameters (parameters ));
125134 }
126135
127- private static int [] getEcParameters (DerElement parameters ) {
136+ private static EncodedOid getEcParameters (DerElement parameters ) {
128137 if (parameters == null ) {
129- return EC_PARAMETERS ;
138+ return ELLIPTIC_CURVE_384_BIT ;
130139 }
131140 Assert .state (parameters .isType (ValueType .ENCODED ), "Key spec should contain encoded parameters" );
132141 DerElement contents = DerElement .of (parameters .getContents ());
133142 Assert .state (contents .isType (ValueType .PRIMITIVE , TagType .OBJECT_IDENTIFIER ),
134143 "Key spec parameters should contain object identifier" );
135- return getEcParameters ( contents . getContents () );
144+ return EncodedOid . of ( contents );
136145 }
137146
138- private static int [] getEcParameters (ByteBuffer bytes ) {
139- int [] result = new int [bytes .remaining ()];
140- for (int i = 0 ; i < result .length ; i ++) {
141- result [i ] = bytes .get () & 0xFF ;
142- }
143- return result ;
144- }
145-
146- private static PKCS8EncodedKeySpec createKeySpecForAlgorithm (byte [] bytes , int [] algorithm , int [] parameters ) {
147+ private static PKCS8EncodedKeySpec createKeySpecForAlgorithm (byte [] bytes , EncodedOid algorithm ,
148+ EncodedOid parameters ) {
147149 try {
148150 DerEncoder encoder = new DerEncoder ();
149151 encoder .integer (0x00 ); // Version 0
@@ -160,7 +162,20 @@ private static PKCS8EncodedKeySpec createKeySpecForAlgorithm(byte[] bytes, int[]
160162 }
161163
162164 private static PKCS8EncodedKeySpec createKeySpecForPkcs8 (byte [] bytes , String password ) {
163- return new PKCS8EncodedKeySpec (bytes );
165+ DerElement ecPrivateKey = DerElement .of (bytes );
166+ Assert .state (ecPrivateKey .isType (ValueType .ENCODED , TagType .SEQUENCE ),
167+ "Key spec should be an ASN.1 encoded sequence" );
168+ DerElement version = DerElement .of (ecPrivateKey .getContents ());
169+ Assert .state (version != null && version .isType (ValueType .PRIMITIVE , TagType .INTEGER ),
170+ "Key spec should start with version" );
171+ DerElement sequence = DerElement .of (ecPrivateKey .getContents ());
172+ Assert .state (sequence != null && sequence .isType (ValueType .ENCODED , TagType .SEQUENCE ),
173+ "Key spec should contain private key" );
174+ DerElement algorithmId = DerElement .of (sequence .getContents ());
175+ Assert .state (algorithmId != null && algorithmId .isType (ValueType .PRIMITIVE , TagType .OBJECT_IDENTIFIER ),
176+ "Key spec container object identifier" );
177+ String algorithmName = ALGORITHMS .get (EncodedOid .of (algorithmId ));
178+ return (algorithmName != null ) ? new PKCS8EncodedKeySpec (bytes , algorithmName ) : new PKCS8EncodedKeySpec (bytes );
164179 }
165180
166181 private static PKCS8EncodedKeySpec createKeySpecForPkcs8Encrypted (byte [] bytes , String password ) {
@@ -231,6 +246,15 @@ private static byte[] decodeBase64(String content) {
231246
232247 private PrivateKey parse (byte [] bytes , String password ) {
233248 PKCS8EncodedKeySpec keySpec = this .keySpecFactory .apply (bytes , password );
249+ if (keySpec .getAlgorithm () != null ) {
250+ try {
251+ KeyFactory keyFactory = KeyFactory .getInstance (keySpec .getAlgorithm ());
252+ return keyFactory .generatePrivate (keySpec );
253+ }
254+ catch (InvalidKeySpecException | NoSuchAlgorithmException ex ) {
255+ // Ignore
256+ }
257+ }
234258 for (String algorithm : this .algorithms ) {
235259 try {
236260 KeyFactory keyFactory = KeyFactory .getInstance (algorithm );
@@ -251,9 +275,9 @@ static class DerEncoder {
251275
252276 private final ByteArrayOutputStream stream = new ByteArrayOutputStream ();
253277
254- void objectIdentifier (int ... encodedObjectIdentifier ) throws IOException {
255- int code = (encodedObjectIdentifier != null ) ? 0x06 : 0x05 ;
256- codeLengthBytes (code , bytes ( encodedObjectIdentifier ) );
278+ void objectIdentifier (EncodedOid encodedOid ) throws IOException {
279+ int code = (encodedOid != null ) ? 0x06 : 0x05 ;
280+ codeLengthBytes (code , ( encodedOid != null ) ? encodedOid . toByteArray () : null );
257281 }
258282
259283 void integer (int ... encodedInteger ) throws IOException {
@@ -449,4 +473,69 @@ private static String getEncryptionAlgorithm(AlgorithmParameters algParameters,
449473
450474 }
451475
476+ /**
477+ * ANS.1 encoded object identifier.
478+ */
479+ static final class EncodedOid {
480+
481+ static final EncodedOid OID_1_2_840_10040_4_1 = EncodedOid .of ("2a8648ce380401" );
482+ static final EncodedOid OID_1_2_840_113549_1_1_1 = EncodedOid .of ("2A864886F70D010101" );
483+ static final EncodedOid OID_1_2_840_113549_1_1_10 = EncodedOid .of ("2a864886f70d01010a" );
484+ static final EncodedOid OID_1_3_101_110 = EncodedOid .of ("2b656e" );
485+ static final EncodedOid OID_1_3_101_111 = EncodedOid .of ("2b656f" );
486+ static final EncodedOid OID_1_3_101_112 = EncodedOid .of ("2b6570" );
487+ static final EncodedOid OID_1_3_101_113 = EncodedOid .of ("2b6571" );
488+ static final EncodedOid OID_1_2_840_10045_2_1 = EncodedOid .of ("2a8648ce3d0201" );
489+ static final EncodedOid OID_1_3_132_0_34 = EncodedOid .of ("2b81040022" );
490+
491+ private final byte [] value ;
492+
493+ private EncodedOid (byte [] value ) {
494+ this .value = value ;
495+ }
496+
497+ byte [] toByteArray () {
498+ return this .value .clone ();
499+ }
500+
501+ @ Override
502+ public boolean equals (Object obj ) {
503+ if (this == obj ) {
504+ return true ;
505+ }
506+ if (obj == null || getClass () != obj .getClass ()) {
507+ return false ;
508+ }
509+ return Arrays .equals (this .value , ((EncodedOid ) obj ).value );
510+ }
511+
512+ @ Override
513+ public int hashCode () {
514+ return Arrays .hashCode (this .value );
515+ }
516+
517+ static EncodedOid of (String hexString ) {
518+ return of (HexFormat .of ().parseHex (hexString ));
519+ }
520+
521+ static EncodedOid of (DerElement derElement ) {
522+ return of (derElement .getContents ());
523+ }
524+
525+ static EncodedOid of (ByteBuffer byteBuffer ) {
526+ return of (byteBuffer .array (), byteBuffer .arrayOffset () + byteBuffer .position (), byteBuffer .remaining ());
527+ }
528+
529+ static EncodedOid of (byte [] bytes ) {
530+ return of (bytes , 0 , bytes .length );
531+ }
532+
533+ static EncodedOid of (byte [] bytes , int off , int len ) {
534+ byte [] value = new byte [len ];
535+ System .arraycopy (bytes , off , value , 0 , len );
536+ return new EncodedOid (value );
537+ }
538+
539+ }
540+
452541}
0 commit comments