3939 */
4040
4141#include "libssh2_priv.h"
42+ #ifdef LIBSSH2_WINCNG
43+ #include "wincng.h" // get MD5 functions
44+ #endif
4245
4346static int
4447readline (char * line , int line_size , FILE * fp )
@@ -112,32 +115,78 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
112115 const char * headerend ,
113116 const unsigned char * passphrase ,
114117 FILE * fp , unsigned char * * data , size_t * datalen )
118+ {
119+ int ret ;
120+ char * filedata = NULL ;
121+ size_t filedata_len ;
122+
123+ fseek (fp , 0L , SEEK_END );
124+ filedata_len = ftell (fp );
125+ fseek (fp , 0L , 0 );
126+
127+ filedata = LIBSSH2_ALLOC (session , filedata_len );
128+ if (!filedata ) {
129+ _libssh2_error (session , LIBSSH2_ERROR_ALLOC ,
130+ "Unable to allocate memory for PEM parsing" );
131+ ret = -1 ;
132+ goto out ;
133+ }
134+
135+ if (fread (filedata , 1 , filedata_len , fp ) != filedata_len ) {
136+ _libssh2_error (session , LIBSSH2_ERROR_FILE ,
137+ "Bad read in PEM parsing" );
138+ ret = -1 ;
139+ goto out ;
140+ }
141+
142+ ret = _libssh2_pem_parse_memory (session , headerbegin , headerend ,
143+ passphrase , filedata , filedata_len ,
144+ data , datalen );
145+
146+ out :
147+ if (filedata ) {
148+ LIBSSH2_FREE (session , filedata );
149+ }
150+ return ret ;
151+ }
152+
153+ int
154+ _libssh2_pem_parse_memory (LIBSSH2_SESSION * session ,
155+ const char * headerbegin ,
156+ const char * headerend ,
157+ const unsigned char * passphrase ,
158+ const char * filedata , size_t filedata_len ,
159+ unsigned char * * data , size_t * datalen )
115160{
116161 char line [LINE_SIZE ];
117162 unsigned char iv [LINE_SIZE ];
118163 char * b64data = NULL ;
119164 size_t b64datalen = 0 ;
165+ size_t off = 0 ;
120166 int ret ;
121- const LIBSSH2_CRYPT_METHOD * method = NULL ;
167+ const LIBSSH2_CRYPT_METHOD * method = NULL ;
122168
123169 do {
124170 * line = '\0' ;
125171
126- if (readline (line , LINE_SIZE , fp )) {
172+ if (readline_memory (line , LINE_SIZE , filedata , filedata_len , & off )) {
127173 return -1 ;
128174 }
175+
176+ if (!* line )
177+ break ;
129178 } while (strcmp (line , headerbegin ) != 0 );
130179
131- if (readline (line , LINE_SIZE , fp )) {
180+ if (readline_memory (line , LINE_SIZE , filedata , filedata_len , & off )) {
132181 return -1 ;
133182 }
134183
135184 if (passphrase &&
136- memcmp (line , crypt_annotation , strlen (crypt_annotation )) == 0 ) {
137- const LIBSSH2_CRYPT_METHOD * * all_methods , * cur_method ;
185+ memcmp (line , crypt_annotation , strlen (crypt_annotation )) == 0 ) {
186+ const LIBSSH2_CRYPT_METHOD * * all_methods , * cur_method ;
138187 int i ;
139188
140- if (readline (line , LINE_SIZE , fp )) {
189+ if (readline_memory (line , LINE_SIZE , filedata , filedata_len , & off )) {
141190 ret = -1 ;
142191 goto out ;
143192 }
@@ -146,31 +195,37 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
146195 /* !checksrc! disable EQUALSNULL 1 */
147196 while ((cur_method = * all_methods ++ ) != NULL ) {
148197 if (* cur_method -> pem_annotation &&
149- memcmp (line , cur_method -> pem_annotation ,
150- strlen (cur_method -> pem_annotation )) == 0 ) {
198+ memcmp (line , cur_method -> pem_annotation ,
199+ strlen (cur_method -> pem_annotation )) == 0 ) {
151200 method = cur_method ;
152201 memcpy (iv , line + strlen (method -> pem_annotation ) + 1 ,
153- 2 * method -> iv_len );
202+ 2 * method -> iv_len );
154203 }
155204 }
156205
157206 /* None of the available crypt methods were able to decrypt the key */
158- if (!method )
159- return -1 ;
207+ if (!method ) {
208+ _libssh2_error (session , LIBSSH2_ERROR_ALGO_UNSUPPORTED ,
209+ "Unable to decrypt PEM, unsupported algorithm" );
210+ ret = -1 ;
211+ goto out ;
212+ }
160213
161214 /* Decode IV from hex */
162215 for (i = 0 ; i < method -> iv_len ; ++ i ) {
163- iv [i ] = (unsigned char )(hex_decode (iv [2 * i ]) << 4 );
164- iv [i ] |= hex_decode (iv [2 * i + 1 ]);
216+ iv [i ] = (unsigned char )(hex_decode (iv [2 * i ]) << 4 );
217+ iv [i ] |= hex_decode (iv [2 * i + 1 ]);
165218 }
166219
167220 /* skip to the next line */
168- if (readline (line , LINE_SIZE , fp )) {
221+ if (readline_memory (line , LINE_SIZE , filedata , filedata_len , & off )) {
169222 ret = -1 ;
170223 goto out ;
171224 }
172225 }
173226
227+ * line = '\0' ;
228+
174229 do {
175230 if (* line ) {
176231 char * tmp ;
@@ -191,7 +246,7 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
191246
192247 * line = '\0' ;
193248
194- if (readline (line , LINE_SIZE , fp )) {
249+ if (readline_memory (line , LINE_SIZE , filedata , filedata_len , & off )) {
195250 ret = -1 ;
196251 goto out ;
197252 }
@@ -217,39 +272,40 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
217272 if (method ) {
218273#if LIBSSH2_MD5_PEM
219274 /* Set up decryption */
220- int free_iv = 0 , free_secret = 0 , len_decrypted = 0 , padding = 0 ;
275+ int free_iv = 0 , free_secret = 0 , len_decrypted = 0 ;
276+ size_t padding = 0 ;
221277 int blocksize = method -> blocksize ;
222278 void * abstract ;
223- unsigned char secret [2 * MD5_DIGEST_LENGTH ];
279+ unsigned char secret [2 * MD5_DIGEST_LENGTH ];
224280 libssh2_md5_ctx fingerprint_ctx ;
225281
226282 /* Perform key derivation (PBKDF1/MD5) */
227283 if (!libssh2_md5_init (& fingerprint_ctx ) ||
228- !libssh2_md5_update (fingerprint_ctx , passphrase ,
229- strlen ((const char * )passphrase )) ||
230- !libssh2_md5_update (fingerprint_ctx , iv , 8 ) ||
231- !libssh2_md5_final (fingerprint_ctx , secret )) {
284+ !libssh2_md5_update (fingerprint_ctx , passphrase ,
285+ strlen ((const char * )passphrase )) ||
286+ !libssh2_md5_update (fingerprint_ctx , iv , 8 ) ||
287+ !libssh2_md5_final (fingerprint_ctx , secret )) {
232288 ret = -1 ;
233289 goto out ;
234290 }
235291 if (method -> secret_len > MD5_DIGEST_LENGTH ) {
236292 if (!libssh2_md5_init (& fingerprint_ctx ) ||
237- !libssh2_md5_update (fingerprint_ctx ,
238- secret , MD5_DIGEST_LENGTH ) ||
239- !libssh2_md5_update (fingerprint_ctx ,
240- passphrase ,
241- strlen ((const char * )passphrase )) ||
242- !libssh2_md5_update (fingerprint_ctx , iv , 8 ) ||
243- !libssh2_md5_final (fingerprint_ctx ,
244- secret + MD5_DIGEST_LENGTH )) {
293+ !libssh2_md5_update (fingerprint_ctx ,
294+ secret , MD5_DIGEST_LENGTH ) ||
295+ !libssh2_md5_update (fingerprint_ctx ,
296+ passphrase ,
297+ strlen ((const char * )passphrase )) ||
298+ !libssh2_md5_update (fingerprint_ctx , iv , 8 ) ||
299+ !libssh2_md5_final (fingerprint_ctx ,
300+ secret + MD5_DIGEST_LENGTH )) {
245301 ret = -1 ;
246302 goto out ;
247303 }
248304 }
249305
250306 /* Initialize the decryption */
251307 if (method -> init (session , method , iv , & free_iv , secret ,
252- & free_secret , 0 , & abstract )) {
308+ & free_secret , 0 , & abstract )) {
253309 _libssh2_explicit_zero ((char * )secret , sizeof (secret ));
254310 _libssh2_explicit_zero (* data , * datalen );
255311 LIBSSH2_FREE (session , * data );
@@ -284,11 +340,11 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
284340 else {
285341 while (len_decrypted <= (int )* datalen - blocksize ) {
286342 if (method -> crypt (session , 0 , * data + len_decrypted , blocksize ,
287- & abstract ,
288- len_decrypted == 0 ? FIRST_BLOCK :
289- ((len_decrypted == (int )* datalen - blocksize ) ?
290- LAST_BLOCK : MIDDLE_BLOCK )
291- )) {
343+ & abstract ,
344+ len_decrypted == 0 ? FIRST_BLOCK :
345+ ((len_decrypted == (int )* datalen - blocksize ) ?
346+ LAST_BLOCK : MIDDLE_BLOCK )
347+ )) {
292348 ret = LIBSSH2_ERROR_DECRYPT ;
293349 _libssh2_explicit_zero ((char * )secret , sizeof (secret ));
294350 method -> dtor (session , & abstract );
@@ -317,6 +373,8 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
317373 _libssh2_explicit_zero ((char * )secret , sizeof (secret ));
318374 method -> dtor (session , & abstract );
319375#else
376+ _libssh2_error (session , LIBSSH2_ERROR_ALGO_UNSUPPORTED ,
377+ "Unable to decrypt PEM, MD5 not enabled" );
320378 ret = -1 ;
321379 goto out ;
322380#endif
@@ -331,74 +389,6 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
331389 return ret ;
332390}
333391
334- int
335- _libssh2_pem_parse_memory (LIBSSH2_SESSION * session ,
336- const char * headerbegin ,
337- const char * headerend ,
338- const char * filedata , size_t filedata_len ,
339- unsigned char * * data , size_t * datalen )
340- {
341- char line [LINE_SIZE ];
342- char * b64data = NULL ;
343- size_t b64datalen = 0 ;
344- size_t off = 0 ;
345- int ret ;
346-
347- do {
348- * line = '\0' ;
349-
350- if (readline_memory (line , LINE_SIZE , filedata , filedata_len , & off )) {
351- return -1 ;
352- }
353- } while (strcmp (line , headerbegin ) != 0 );
354-
355- * line = '\0' ;
356-
357- do {
358- if (* line ) {
359- char * tmp ;
360- size_t linelen ;
361-
362- linelen = strlen (line );
363- tmp = LIBSSH2_REALLOC (session , b64data , b64datalen + linelen );
364- if (!tmp ) {
365- _libssh2_error (session , LIBSSH2_ERROR_ALLOC ,
366- "Unable to allocate memory for PEM parsing" );
367- ret = -1 ;
368- goto out ;
369- }
370- memcpy (tmp + b64datalen , line , linelen );
371- b64data = tmp ;
372- b64datalen += linelen ;
373- }
374-
375- * line = '\0' ;
376-
377- if (readline_memory (line , LINE_SIZE , filedata , filedata_len , & off )) {
378- ret = -1 ;
379- goto out ;
380- }
381- } while (strcmp (line , headerend ) != 0 );
382-
383- if (!b64data ) {
384- return -1 ;
385- }
386-
387- if (_libssh2_base64_decode (session , (char * * ) data , datalen ,
388- b64data , b64datalen )) {
389- ret = -1 ;
390- goto out ;
391- }
392-
393- ret = 0 ;
394- out :
395- if (b64data ) {
396- _libssh2_explicit_zero (b64data , b64datalen );
397- LIBSSH2_FREE (session , b64data );
398- }
399- return ret ;
400- }
401-
402392/* OpenSSH formatted keys */
403393#define AUTH_MAGIC "openssh-key-v1"
404394#define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
0 commit comments