summaryrefslogtreecommitdiff
path: root/libs/libssh2/src/pem.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libssh2/src/pem.c')
-rw-r--r--libs/libssh2/src/pem.c158
1 files changed, 93 insertions, 65 deletions
diff --git a/libs/libssh2/src/pem.c b/libs/libssh2/src/pem.c
index 53f58c2ef1..912498c5d3 100644
--- a/libs/libssh2/src/pem.c
+++ b/libs/libssh2/src/pem.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2007 The Written Word, Inc.
- * Copyright (C) 2008, Simon Josefsson
+/* Copyright (C) The Written Word, Inc.
+ * Copyright (C) Simon Josefsson
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -34,6 +34,8 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
*/
#include "libssh2_priv.h"
@@ -100,20 +102,27 @@ static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED";
static unsigned char hex_decode(char digit)
{
- return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0');
+ return (unsigned char)
+ ((digit >= 'A') ? (0xA + (digit - 'A')) : (digit - '0'));
}
+/* Hack to fix builds with crypto backends with MD5 support disabled.
+ FIXME: Honor our LIBSSH2_MD5 macro for MD5-dependent logic. */
+#ifdef OPENSSL_NO_MD5
+#define MD5_DIGEST_LENGTH 16
+#endif
+
int
_libssh2_pem_parse(LIBSSH2_SESSION * session,
const char *headerbegin,
const char *headerend,
const unsigned char *passphrase,
- FILE * fp, unsigned char **data, unsigned int *datalen)
+ FILE * fp, unsigned char **data, size_t *datalen)
{
char line[LINE_SIZE];
unsigned char iv[LINE_SIZE];
char *b64data = NULL;
- unsigned int b64datalen = 0;
+ size_t b64datalen = 0;
int ret;
const LIBSSH2_CRYPT_METHOD *method = NULL;
@@ -141,7 +150,8 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
}
all_methods = libssh2_crypt_methods();
- while((cur_method = *all_methods++)) {
+ /* !checksrc! disable EQUALSNULL 1 */
+ while((cur_method = *all_methods++) != NULL) {
if(*cur_method->pem_annotation &&
memcmp(line, cur_method->pem_annotation,
strlen(cur_method->pem_annotation)) == 0) {
@@ -152,12 +162,12 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
}
/* None of the available crypt methods were able to decrypt the key */
- if(method == NULL)
+ if(!method)
return -1;
/* Decode IV from hex */
for(i = 0; i < method->iv_len; ++i) {
- iv[i] = hex_decode(iv[2*i]) << 4;
+ iv[i] = (unsigned char)(hex_decode(iv[2*i]) << 4);
iv[i] |= hex_decode(iv[2*i + 1]);
}
@@ -176,6 +186,8 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
linelen = strlen(line);
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
if(!tmp) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for PEM parsing");
ret = -1;
goto out;
}
@@ -196,7 +208,7 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
return -1;
}
- if(libssh2_base64_decode(session, (char **) data, datalen,
+ if(_libssh2_base64_decode(session, (char **) data, datalen,
b64data, b64datalen)) {
ret = -1;
goto out;
@@ -256,7 +268,11 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
while(len_decrypted <= (int)*datalen - blocksize) {
if(method->crypt(session, *data + len_decrypted, blocksize,
- &abstract)) {
+ &abstract,
+ len_decrypted == 0 ? FIRST_BLOCK :
+ ((len_decrypted == (int)*datalen - blocksize) ?
+ LAST_BLOCK : MIDDLE_BLOCK)
+ )) {
ret = LIBSSH2_ERROR_DECRYPT;
_libssh2_explicit_zero((char *)secret, sizeof(secret));
method->dtor(session, &abstract);
@@ -279,7 +295,7 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
}
ret = 0;
- out:
+out:
if(b64data) {
_libssh2_explicit_zero(b64data, b64datalen);
LIBSSH2_FREE(session, b64data);
@@ -292,11 +308,11 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
const char *headerbegin,
const char *headerend,
const char *filedata, size_t filedata_len,
- unsigned char **data, unsigned int *datalen)
+ unsigned char **data, size_t *datalen)
{
char line[LINE_SIZE];
char *b64data = NULL;
- unsigned int b64datalen = 0;
+ size_t b64datalen = 0;
size_t off = 0;
int ret;
@@ -319,6 +335,8 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
linelen = strlen(line);
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
if(!tmp) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for PEM parsing");
ret = -1;
goto out;
}
@@ -339,14 +357,14 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
return -1;
}
- if(libssh2_base64_decode(session, (char **) data, datalen,
+ if(_libssh2_base64_decode(session, (char **) data, datalen,
b64data, b64datalen)) {
ret = -1;
goto out;
}
ret = 0;
- out:
+out:
if(b64data) {
_libssh2_explicit_zero(b64data, b64datalen);
LIBSSH2_FREE(session, b64data);
@@ -378,7 +396,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
unsigned char *key_part = NULL;
unsigned char *iv_part = NULL;
unsigned char *f = NULL;
- unsigned int f_len = 0;
+ size_t f_len = 0;
int ret = 0, keylen = 0, ivlen = 0, total_len = 0;
size_t kdf_len = 0, tmp_len = 0, salt_len = 0;
@@ -386,10 +404,10 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
*decrypted_buf = NULL;
/* decode file */
- if(libssh2_base64_decode(session, (char **)&f, &f_len,
- b64data, b64datalen)) {
- ret = -1;
- goto out;
+ if(_libssh2_base64_decode(session, (char **)&f, &f_len,
+ b64data, b64datalen)) {
+ ret = -1;
+ goto out;
}
/* Parse the file */
@@ -421,7 +439,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) ||
tmp_len == 0) {
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "kdfname is missing");
+ "kdfname is missing");
goto out;
}
@@ -436,7 +454,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
kdf_buf.len = kdf_len;
}
- if((passphrase == NULL || strlen((const char *)passphrase) == 0) &&
+ if((!passphrase || strlen((const char *)passphrase) == 0) &&
strcmp((const char *)ciphername, "none") != 0) {
/* passphrase required */
ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
@@ -452,8 +470,8 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
if(!strcmp((const char *)kdfname, "none") &&
strcmp((const char *)ciphername, "none") != 0) {
- ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "invalid format");
+ ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "invalid format");
goto out;
}
@@ -474,7 +492,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Private key data not found");
+ "Private key data not found");
goto out;
}
@@ -486,7 +504,8 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
all_methods = libssh2_crypt_methods();
- while((cur_method = *all_methods++)) {
+ /* !checksrc! disable EQUALSNULL 1 */
+ while((cur_method = *all_methods++) != NULL) {
if(*cur_method->name &&
memcmp(ciphername, cur_method->name,
strlen(cur_method->name)) == 0) {
@@ -496,9 +515,9 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
/* None of the available crypt methods were able to decrypt the key */
- if(method == NULL) {
+ if(!method) {
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "No supported cipher found");
+ "No supported cipher found");
goto out;
}
}
@@ -513,16 +532,15 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
total_len = keylen + ivlen;
key = LIBSSH2_CALLOC(session, total_len);
- if(key == NULL) {
+ if(!key) {
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Could not alloc key");
+ "Could not alloc key");
goto out;
}
- if(strcmp((const char *)kdfname, "bcrypt") == 0 &&
- passphrase != NULL) {
+ if(strcmp((const char *)kdfname, "bcrypt") == 0 && passphrase) {
if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) ||
- (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) {
+ (_libssh2_get_u32(&kdf_buf, &rounds) != 0)) {
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"kdf contains unexpected values");
LIBSSH2_FREE(session, key);
@@ -541,7 +559,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
}
else {
ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED,
- "bcrypted without passphrase");
+ "bcrypted without passphrase");
LIBSSH2_FREE(session, key);
goto out;
}
@@ -550,14 +568,14 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
blocksize = method->blocksize;
key_part = LIBSSH2_CALLOC(session, keylen);
- if(key_part == NULL) {
+ if(!key_part) {
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Could not alloc key part");
goto out;
}
iv_part = LIBSSH2_CALLOC(session, ivlen);
- if(iv_part == NULL) {
+ if(!iv_part) {
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Could not alloc iv part");
goto out;
@@ -568,7 +586,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
/* Initialize the decryption */
if(method->init(session, method, iv_part, &free_iv, key_part,
- &free_secret, 0, &abstract)) {
+ &free_secret, 0, &abstract)) {
ret = LIBSSH2_ERROR_DECRYPT;
goto out;
}
@@ -583,7 +601,11 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
while((size_t)len_decrypted <= decrypted.len - blocksize) {
if(method->crypt(session, decrypted.data + len_decrypted,
blocksize,
- &abstract)) {
+ &abstract,
+ len_decrypted == 0 ? FIRST_BLOCK : (
+ ((size_t)len_decrypted == decrypted.len - blocksize) ?
+ LAST_BLOCK : MIDDLE_BLOCK)
+ )) {
ret = LIBSSH2_ERROR_DECRYPT;
method->dtor(session, &abstract);
goto out;
@@ -602,13 +624,13 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
if(_libssh2_get_u32(&decrypted, &check1) != 0 ||
_libssh2_get_u32(&decrypted, &check2) != 0 ||
check1 != check2) {
- _libssh2_error(session, LIBSSH2_ERROR_PROTO,
- "Private key unpack failed (correct password?)");
- ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
- goto out;
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Private key unpack failed (correct password?)");
+ ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
+ goto out;
}
- if(decrypted_buf != NULL) {
+ if(decrypted_buf) {
/* copy data to out-going buffer */
struct string_buf *out_buf = _libssh2_string_buf_new(session);
if(!out_buf) {
@@ -619,7 +641,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
}
out_buf->data = LIBSSH2_CALLOC(session, decrypted.len);
- if(out_buf->data == NULL) {
+ if(!out_buf->data) {
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for "
"decrypted struct");
@@ -664,7 +686,7 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
{
char line[LINE_SIZE];
char *b64data = NULL;
- unsigned int b64datalen = 0;
+ size_t b64datalen = 0;
int ret = 0;
/* read file */
@@ -690,6 +712,8 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
linelen = strlen(line);
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
if(!tmp) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for PEM parsing");
ret = -1;
goto out;
}
@@ -713,7 +737,7 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
ret = _libssh2_openssh_pem_parse_data(session,
passphrase,
(const char *)b64data,
- (size_t)b64datalen,
+ b64datalen,
decrypted_buf);
if(b64data) {
@@ -734,21 +758,22 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
{
char line[LINE_SIZE];
char *b64data = NULL;
- unsigned int b64datalen = 0;
+ size_t b64datalen = 0;
size_t off = 0;
int ret;
- if(filedata == NULL || filedata_len <= 0) {
- return -1;
- }
+ if(!filedata || filedata_len <= 0)
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Error parsing PEM: filedata missing");
do {
*line = '\0';
- if(off >= filedata_len) {
- return -1;
- }
+ if(off >= filedata_len)
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Error parsing PEM: "
+ "OpenSSH header not found");
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
return -1;
@@ -759,14 +784,16 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
*line = '\0';
do {
- if (*line) {
+ if(*line) {
char *tmp;
size_t linelen;
linelen = strlen(line);
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
if(!tmp) {
- ret = -1;
+ ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for "
+ "PEM parsing");
goto out;
}
memcpy(tmp + b64datalen, line, linelen);
@@ -777,7 +804,8 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
*line = '\0';
if(off >= filedata_len) {
- ret = -1;
+ ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Error parsing PEM: offset out of bounds");
goto out;
}
@@ -787,9 +815,9 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
}
} while(strcmp(line, OPENSSH_HEADER_END) != 0);
- if(!b64data) {
- return -1;
- }
+ if(!b64data)
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Error parsing PEM: base 64 data missing");
ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data,
b64datalen, decrypted_buf);
@@ -805,7 +833,7 @@ out:
static int
read_asn1_length(const unsigned char *data,
- unsigned int datalen, unsigned int *len)
+ size_t datalen, size_t *len)
{
unsigned int lenlen;
int nextpos;
@@ -839,9 +867,9 @@ read_asn1_length(const unsigned char *data,
}
int
-_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
+_libssh2_pem_decode_sequence(unsigned char **data, size_t *datalen)
{
- unsigned int len;
+ size_t len;
int lenlen;
if(*datalen < 1) {
@@ -867,10 +895,10 @@ _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
}
int
-_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
+_libssh2_pem_decode_integer(unsigned char **data, size_t *datalen,
unsigned char **i, unsigned int *ilen)
{
- unsigned int len;
+ size_t len;
int lenlen;
if(*datalen < 1) {
@@ -893,7 +921,7 @@ _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
*datalen -= lenlen;
*i = *data;
- *ilen = len;
+ *ilen = (unsigned int)len;
*data += len;
*datalen -= len;