1515
1616package software .amazon .awssdk .services .signin .internal ;
1717
18- import java .io .ByteArrayInputStream ;
19- import java .io .IOException ;
2018import java .math .BigInteger ;
19+ import java .nio .BufferUnderflowException ;
20+ import java .nio .ByteBuffer ;
2121import java .security .AlgorithmParameters ;
2222import java .security .KeyFactory ;
2323import java .security .NoSuchAlgorithmException ;
3838@ SdkInternalApi
3939public final class EcKeyLoader {
4040
41- public static final String SECP_256_R1_STD_NAME = "secp256r1" ;
42- public static final int DER_SEQUENCE_TAG = 0x30 ;
43- public static final int DER_INTEGER_TAG = 0x02 ;
44- public static final int DER_OCTET_STRING_TAG = 0x04 ;
45- public static final int DER_BIT_STRING_TAG = 0x03 ;
46- public static final int DER_OPTIONAL_SEQ_PARAM_0 = 0xA0 ;
47- public static final int DER_OPTIONAL_SEQ_PARAM_1 = 0xA1 ;
48- public static final int DER_OBJECT_IDENTIFIER_TAG = 0x06 ;
49- public static final int SEC1_VERSION = 1 ;
41+ private static final String SECP_256_R1_STD_NAME = "secp256r1" ;
42+
43+ private static final byte DER_SEQUENCE_TAG = 0x30 ;
44+ private static final byte DER_INTEGER_TAG = 0x02 ;
45+ private static final byte DER_OCTET_STRING_TAG = 0x04 ;
46+ private static final byte DER_BIT_STRING_TAG = 0x03 ;
47+ private static final byte DER_OPTIONAL_SEQ_PARAM_0 = (byte ) 0xA0 ;
48+ private static final byte DER_OPTIONAL_SEQ_PARAM_1 = (byte ) 0xA1 ;
49+ private static final byte DER_OBJECT_IDENTIFIER_TAG = 0x06 ;
50+
51+ private static final int SEC1_VERSION = 1 ;
52+
5053 // bytes for "1.2.840.10045.3.1.7" - the OID for secp256r1 aka prime256v1/NIST P-256
5154 private static byte [] SECP_256_R1_OID_BYTES = new byte [] {0x2A , (byte ) 0x86 , 0x48 , (byte ) 0xCE , 0x3D , 0x03 , 0x01 , 0x07 };
5255
@@ -131,67 +134,65 @@ private static class ParsedEcKey {
131134 */
132135 private static ParsedEcKey parseSec1 (byte [] der ) {
133136 ParsedEcKey result = new ParsedEcKey ();
134- ByteArrayInputStream in = new ByteArrayInputStream (der );
137+ ByteBuffer buffer = ByteBuffer . wrap (der );
135138 int len ;
136139 try {
137- if (in . read () != DER_SEQUENCE_TAG ) {
140+ if (buffer . get () != DER_SEQUENCE_TAG ) {
138141 throw new IllegalArgumentException (
139142 "Invalid SEC1 Private Key: Not a SEQUENCE" );
140143 }
141- readLength (in );
144+ readLength (buffer );
142145
143146 // validate the version
144- if (in . read () != DER_INTEGER_TAG ) {
147+ if (buffer . get () != DER_INTEGER_TAG ) {
145148 throw new IllegalArgumentException (
146149 "Invalid SEC1 Private Key: Expected INTEGER" );
147150 }
148- len = readLength (in );
149- if (len != 1 || in . read () != SEC1_VERSION ) {
151+ len = readLength (buffer );
152+ if (len != 1 || buffer . get () != SEC1_VERSION ) {
150153 throw new IllegalArgumentException ("Invalid SEC1 Private Key: invalid version" );
151154 }
152155
153156 // read private key
154- if (in . read () != DER_OCTET_STRING_TAG ) {
157+ if (buffer . get () != DER_OCTET_STRING_TAG ) {
155158 throw new IllegalArgumentException (
156159 "Invalid SEC1 Private Key: Expected OCTET STRING" );
157160 }
158- len = readLength (in );
161+ len = readLength (buffer );
159162
160163 byte [] privateKeyBytes = new byte [len ];
161- in . read (privateKeyBytes );
164+ buffer . get (privateKeyBytes );
162165 result .privateScalar = new BigInteger (1 , privateKeyBytes );
163166
164- while (in .available () > 0 ) {
165- int tag = in .read ();
166- if (tag == -1 ) {
167- break ;
168- }
169- len = readLength (in );
167+ while (buffer .hasRemaining ()) {
168+ byte tag = buffer .get ();
169+ len = readLength (buffer );
170170 if (tag == DER_OPTIONAL_SEQ_PARAM_0 ) { // [0] parameters (curve OID)
171- if (in . read () != DER_OBJECT_IDENTIFIER_TAG ) {
172- throw new IOException (
171+ if (buffer . get () != DER_OBJECT_IDENTIFIER_TAG ) {
172+ throw new IllegalArgumentException (
173173 "Invalid SEC1 Private Key: Expected OID" );
174174 }
175- int oidLen = readLength (in );
175+ int oidLen = readLength (buffer );
176176 byte [] oid = new byte [oidLen ];
177- in . read (oid );
177+ buffer . get (oid );
178178 result .curveOid = oid ;
179179 } else if (tag == DER_OPTIONAL_SEQ_PARAM_1 ) { // [1] parameters public key (BIT STRING)
180- int bitTag = in . read ();
180+ byte bitTag = buffer . get ();
181181 if (bitTag != DER_BIT_STRING_TAG ) {
182- throw new IOException (
182+ throw new IllegalArgumentException (
183183 "Invalid SEC1 Private Key: Expected BIT STRING" );
184184 }
185- int bitLen = readLength (in );
185+ int bitLen = readLength (buffer );
186186 byte [] bitString = new byte [bitLen ];
187- in . read (bitString );
187+ buffer . get (bitString );
188188 // First byte of BIT STRING is the unused bits count, skip it
189189 result .publicBytes = java .util .Arrays .copyOfRange (bitString , 1 , bitString .length );
190190 } else {
191- in .skip (len ); // ignore unknown
191+ // ignore unknown
192+ buffer .position (buffer .position () + len );
192193 }
193194 }
194- } catch (IOException e ) {
195+ } catch (BufferUnderflowException e ) {
195196 throw new IllegalArgumentException ("Invalid SEC1 Private Key: failed to parse." , e );
196197 }
197198 return result ;
@@ -213,37 +214,36 @@ public static byte[] pemToDer(String pem) {
213214 * Read a length from a DER byte input stream. lengths may be either a single byte (short form) or multiple bytes. If the
214215 * first bit is 0, then the remaining 7 bits give the length directly (short form). If the first bit is 1, then the next 7
215216 * bits give the number of bytes to read for the length. Eg: [0x82 0x01 0xF4] means the length is 2 bytes long (0x82) and the
216- * length is 500 (0x01F4)
217+ * length is 500 (0x01F4).
217218 *
218- * @param in - byte input stream to read from.
219+ * Throws BufferUnderflowException if there are insufficient bytes
220+ *
221+ * @param buffer - byte buffer to read from
219222 * @return the length
220- * @throws IOException
221223 */
222- private static int readLength (ByteArrayInputStream in ) throws IOException {
223- int b = in .read ();
224- if (b < 0 ) {
225- throw new IOException ("Unexpected EOF while reading length" );
226- }
224+ private static int readLength (ByteBuffer buffer ) {
225+ int b = buffer .get () & 0xFF ; // convert signed byte to unsigned int
226+
227227 // if the high (first) bit is 0, then the length is a single byte, return it as is.
228228 if ((b & 0x80 ) == 0 ) {
229229 return b ;
230230 }
231231 // remove the leading 1 bit, this should give the number of bytes for the length
232232 int num = b & 0x7F ;
233233 if (num == 0 ) {
234- throw new IOException ("Indefinite lengths not supported" );
234+ throw new IllegalArgumentException ("Indefinite lengths not supported" );
235235 }
236236 // limit to 4 bytes, supported keys will never have more than 4 bytes of length
237237 if (num > 4 ) {
238- throw new IOException ("Too many bytes in length" );
238+ throw new IllegalArgumentException ("Too many bytes in length" );
239239 }
240240 int val = 0 ;
241241
242242 // construct the length by reading num bytes from the input byte stream.
243243 for (int i = 0 ; i < num ; i ++) {
244- int nb = in . read () ;
244+ int nb = buffer . get () & 0xFF ;
245245 if (nb < 0 ) {
246- throw new IOException ("Unexpected EOF in length bytes" );
246+ throw new IllegalArgumentException ("Unexpected EOF in length bytes" );
247247 }
248248 val = (val << 8 ) | (nb & 0xFF );
249249 }
0 commit comments