diff options
Diffstat (limited to 'libs/libssh2/src/pem.c')
-rw-r--r-- | libs/libssh2/src/pem.c | 158 |
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; |